markdown_exec 2.3.0 → 2.4.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 +11 -2
- data/CHANGELOG.md +19 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +32 -8
- data/bats/bats.bats +33 -0
- data/bats/block-types.bats +56 -0
- data/bats/cli.bats +74 -0
- data/bats/fail.bats +11 -0
- data/bats/history.bats +34 -0
- data/bats/markup.bats +66 -0
- data/bats/mde.bats +29 -0
- data/bats/options.bats +92 -0
- data/bats/test_helper.bash +152 -0
- data/bin/tab_completion.sh +44 -20
- data/docs/dev/block-type-opts.md +10 -0
- data/docs/dev/block-type-port.md +24 -0
- data/docs/dev/block-type-vars.md +7 -0
- data/docs/dev/pass-through-arguments.md +8 -0
- data/docs/dev/specs-import.md +9 -0
- data/docs/dev/specs.md +83 -0
- data/docs/dev/text-decoration.md +7 -0
- data/examples/bash-blocks.md +4 -4
- data/examples/block-names.md +2 -2
- data/examples/import0.md +23 -0
- data/examples/import1.md +13 -0
- data/examples/link-blocks-vars.md +3 -3
- data/examples/opts-blocks-require.md +6 -6
- data/examples/table-markup.md +31 -0
- data/examples/text-markup.md +58 -0
- data/examples/vars-blocks.md +2 -2
- data/examples/wrap.md +87 -9
- data/lib/ansi_formatter.rb +12 -6
- data/lib/ansi_string.rb +153 -0
- data/lib/argument_processor.rb +160 -0
- data/lib/cached_nested_file_reader.rb +4 -2
- data/lib/ce_get_cost_and_usage.rb +4 -3
- data/lib/cli.rb +1 -1
- data/lib/colorize.rb +39 -11
- data/lib/constants.rb +17 -0
- data/lib/directory_searcher.rb +4 -2
- data/lib/doh.rb +190 -0
- data/lib/env.rb +1 -1
- data/lib/exceptions.rb +9 -6
- data/lib/fcb.rb +0 -199
- data/lib/filter.rb +18 -5
- data/lib/find_files.rb +8 -3
- data/lib/format_table.rb +406 -0
- data/lib/hash_delegator.rb +888 -603
- data/lib/hierarchy_string.rb +113 -25
- data/lib/input_sequencer.rb +16 -10
- data/lib/instance_method_wrapper.rb +2 -1
- data/lib/layered_hash.rb +143 -0
- data/lib/link_history.rb +22 -8
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +413 -165
- data/lib/mdoc.rb +27 -34
- data/lib/menu.src.yml +825 -710
- data/lib/menu.yml +799 -703
- data/lib/namer.rb +6 -12
- data/lib/object_present.rb +1 -1
- data/lib/option_value.rb +7 -3
- data/lib/poly.rb +33 -14
- data/lib/resize_terminal.rb +60 -52
- data/lib/saved_assets.rb +45 -34
- data/lib/saved_files_matcher.rb +6 -3
- data/lib/streams_out.rb +7 -1
- data/lib/table_extractor.rb +166 -0
- data/lib/tap.rb +5 -6
- data/lib/text_analyzer.rb +144 -8
- metadata +26 -3
- data/lib/std_out_err_logger.rb +0 -119
data/lib/hash_delegator.rb
CHANGED
@@ -17,6 +17,7 @@ require 'tmpdir'
|
|
17
17
|
require 'tty-prompt'
|
18
18
|
require 'yaml'
|
19
19
|
|
20
|
+
require_relative 'ansi_string'
|
20
21
|
require_relative 'array'
|
21
22
|
require_relative 'array_util'
|
22
23
|
require_relative 'block_label'
|
@@ -27,6 +28,7 @@ require_relative 'directory_searcher'
|
|
27
28
|
require_relative 'exceptions'
|
28
29
|
require_relative 'fcb'
|
29
30
|
require_relative 'filter'
|
31
|
+
require_relative 'format_table'
|
30
32
|
require_relative 'fout'
|
31
33
|
require_relative 'hash'
|
32
34
|
require_relative 'hierarchy_string'
|
@@ -35,11 +37,13 @@ require_relative 'mdoc'
|
|
35
37
|
require_relative 'namer'
|
36
38
|
require_relative 'regexp'
|
37
39
|
require_relative 'resize_terminal'
|
38
|
-
require_relative 'std_out_err_logger'
|
39
40
|
require_relative 'streams_out'
|
40
41
|
require_relative 'string_util'
|
42
|
+
require_relative 'table_extractor'
|
41
43
|
require_relative 'text_analyzer'
|
42
44
|
|
45
|
+
require_relative 'argument_processor'
|
46
|
+
|
43
47
|
$pd = false unless defined?($pd)
|
44
48
|
|
45
49
|
class String
|
@@ -52,17 +56,20 @@ end
|
|
52
56
|
|
53
57
|
module HashDelegatorSelf
|
54
58
|
# Applies an ANSI color method to a string using a specified color key.
|
55
|
-
# The method retrieves the color method from the provided hash. If the
|
56
|
-
# is not present in the hash, it uses a default color method.
|
59
|
+
# The method retrieves the color method from the provided hash. If the
|
60
|
+
# color key is not present in the hash, it uses a default color method.
|
57
61
|
# @param string [String] The string to be colored.
|
58
|
-
# @param color_methods [Hash] A hash where keys are color names
|
59
|
-
#
|
60
|
-
# @param
|
62
|
+
# @param color_methods [Hash] A hash where keys are color names
|
63
|
+
# (String/Symbol) and values are color methods.
|
64
|
+
# @param color_key [String, Symbol] The key representing the desired
|
65
|
+
# color method in the color_methods hash.
|
66
|
+
# @param default_method [String] (optional) Default color method to
|
67
|
+
# use if color_key is not found in color_methods. Defaults to 'plain'.
|
61
68
|
# @return [String] The colored string.
|
62
69
|
def apply_color_from_hash(string, color_methods, color_key,
|
63
70
|
default_method: 'plain')
|
64
71
|
color_method = color_methods.fetch(color_key, default_method).to_sym
|
65
|
-
string.to_s.send(color_method)
|
72
|
+
AnsiString.new(string.to_s).send(color_method)
|
66
73
|
end
|
67
74
|
|
68
75
|
# # Enhanced `apply_color_from_hash` method to support dynamic color transformations
|
@@ -84,15 +91,21 @@ module HashDelegatorSelf
|
|
84
91
|
# colored_string = apply_color_from_hash(string, color_transformations, :red)
|
85
92
|
# puts colored_string # This will print the string in red
|
86
93
|
|
87
|
-
# Searches for the first element in a collection where the specified
|
88
|
-
#
|
94
|
+
# Searches for the first element in a collection where the specified
|
95
|
+
# message sent to an element matches a given value.
|
96
|
+
# This method is particularly useful for finding a specific hash-like
|
97
|
+
# object within an enumerable collection.
|
89
98
|
# If no match is found, it returns a specified default value.
|
90
99
|
#
|
91
100
|
# @param blocks [Enumerable] The collection of hash-like objects to search.
|
92
|
-
# @param msg [Symbol, String] The message to send to each element of
|
93
|
-
#
|
94
|
-
# @param
|
95
|
-
#
|
101
|
+
# @param msg [Symbol, String] The message to send to each element of
|
102
|
+
# the collection.
|
103
|
+
# @param value [Object] The value to match against the result of the message
|
104
|
+
# sent to each element.
|
105
|
+
# @param default [Object, nil] The default value to return if no match is
|
106
|
+
# found (optional).
|
107
|
+
# @return [Object, nil] The first matching element or the default value if
|
108
|
+
# no match is found.
|
96
109
|
def block_find(blocks, msg, value, default = nil)
|
97
110
|
blocks.find { |item| item.send(msg) == value } || default
|
98
111
|
end
|
@@ -110,11 +123,13 @@ module HashDelegatorSelf
|
|
110
123
|
end
|
111
124
|
|
112
125
|
# Creates a file at the specified path, writes the given content to it,
|
113
|
-
# and sets file permissions if required. Handles any errors encountered
|
126
|
+
# and sets file permissions if required. Handles any errors encountered
|
127
|
+
# during the process.
|
114
128
|
#
|
115
129
|
# @param file_path [String] The path where the file will be created.
|
116
130
|
# @param content [String] The content to write into the file.
|
117
|
-
# @param chmod_value [Integer] The file permission value to set;
|
131
|
+
# @param chmod_value [Integer] The file permission value to set;
|
132
|
+
# skips if zero.
|
118
133
|
def create_file_and_write_string_with_permissions(file_path, content,
|
119
134
|
chmod_value)
|
120
135
|
create_directory_for_file(file_path)
|
@@ -128,7 +143,8 @@ module HashDelegatorSelf
|
|
128
143
|
# Dir::Tmpname.create(self.class.to_s) { |path| path }
|
129
144
|
# end
|
130
145
|
|
131
|
-
# Updates the title of an FCB object from its body content if the title
|
146
|
+
# Updates the title of an FCB object from its body content if the title
|
147
|
+
# is nil or empty.
|
132
148
|
def default_block_title_from_body(fcb)
|
133
149
|
return unless fcb.title.nil? || fcb.title.empty?
|
134
150
|
|
@@ -174,7 +190,8 @@ module HashDelegatorSelf
|
|
174
190
|
|
175
191
|
# Indents all lines in a given string with a specified indentation string.
|
176
192
|
# @param body [String] A multi-line string to be indented.
|
177
|
-
# @param indent [String] The string used for indentation
|
193
|
+
# @param indent [String] The string used for indentation
|
194
|
+
# (default is an empty string).
|
178
195
|
# @return [String] A single string with each line indented as specified.
|
179
196
|
def indent_all_lines(body, indent = nil)
|
180
197
|
return body unless indent&.non_empty?
|
@@ -271,13 +288,51 @@ module HashDelegatorSelf
|
|
271
288
|
File.chmod(chmod_value, file_path)
|
272
289
|
end
|
273
290
|
|
291
|
+
# find tables in multiple lines and format horizontally
|
292
|
+
def tables_into_columns!(blocks_menu, delegate_object)
|
293
|
+
return unless delegate_object[:tables_into_columns]
|
294
|
+
|
295
|
+
lines = blocks_menu.map(&:oname)
|
296
|
+
text_tables = TableExtractor.extract_tables(lines)
|
297
|
+
return unless text_tables.count.positive?
|
298
|
+
|
299
|
+
text_tables.each do |match|
|
300
|
+
range = match[:start_index]..(match[:start_index] + match[:rows] - 1)
|
301
|
+
lines = blocks_menu[range].map(&:oname)
|
302
|
+
formatted = MarkdownTableFormatter.format_table(
|
303
|
+
lines,
|
304
|
+
match[:columns],
|
305
|
+
decorate: {
|
306
|
+
border: delegate_object[:table_border_color],
|
307
|
+
header_row: delegate_object[:table_header_row_color],
|
308
|
+
row: delegate_object[:table_row_color],
|
309
|
+
separator_line: delegate_object[:table_separator_line_color]
|
310
|
+
}
|
311
|
+
)
|
312
|
+
|
313
|
+
if formatted.count == range.size
|
314
|
+
# read indentation from first line
|
315
|
+
indent = blocks_menu[range.first].oname.split('|', 2).first
|
316
|
+
|
317
|
+
# replace text in each block
|
318
|
+
range.each.with_index do |block_ind, ind|
|
319
|
+
### format oname to dname
|
320
|
+
blocks_menu[block_ind].dname = indent + formatted[ind]
|
321
|
+
end
|
322
|
+
else
|
323
|
+
warn [__LINE__, range, lines, formatted].inspect
|
324
|
+
raise 'Invalid result from MarkdownTableFormatter.format_table()'
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
274
329
|
# Creates a TTY prompt with custom settings. Specifically, it disables the default 'cross' symbol and
|
275
330
|
# defines a lambda function to handle interrupts.
|
276
331
|
# @return [TTY::Prompt] A new TTY::Prompt instance with specified configurations.
|
277
332
|
def tty_prompt_without_disabled_symbol
|
278
333
|
TTY::Prompt.new(
|
279
334
|
interrupt: lambda {
|
280
|
-
puts
|
335
|
+
puts # next line in case not at start
|
281
336
|
raise TTY::Reader::InputInterrupt
|
282
337
|
},
|
283
338
|
symbols: { cross: ' ' }
|
@@ -289,7 +344,7 @@ module HashDelegatorSelf
|
|
289
344
|
# If the fcb has a body and meets certain conditions, it yields to the given block.
|
290
345
|
#
|
291
346
|
# @param fcb [Object] The fcb object whose attributes are to be updated.
|
292
|
-
# @param
|
347
|
+
# @param selected_types [Array<Symbol>] A list of message types to determine if yielding is applicable.
|
293
348
|
# @param block [Block] An optional block to yield to if conditions are met.
|
294
349
|
def update_menu_attrib_yield_selected(fcb:, messages:, configuration: {},
|
295
350
|
&block)
|
@@ -303,10 +358,10 @@ module HashDelegatorSelf
|
|
303
358
|
|
304
359
|
# Yields a line as a new block if the selected message type includes :line.
|
305
360
|
# @param [String] line The line to be processed.
|
306
|
-
# @param [Array<Symbol>]
|
361
|
+
# @param [Array<Symbol>] selected_types A list of message types to check.
|
307
362
|
# @param [Proc] block The block to be called with the line data.
|
308
|
-
def yield_line_if_selected(line,
|
309
|
-
return unless block &&
|
363
|
+
def yield_line_if_selected(line, selected_types, &block)
|
364
|
+
return unless block && block_type_selected?(selected_types, :line)
|
310
365
|
|
311
366
|
block.call(:line, MarkdownExec::FCB.new(body: [line]))
|
312
367
|
end
|
@@ -480,7 +535,8 @@ module MarkdownExec
|
|
480
535
|
end
|
481
536
|
|
482
537
|
class HashDelegatorParent
|
483
|
-
attr_accessor :most_recent_loaded_filename, :pass_args, :run_state
|
538
|
+
attr_accessor :most_recent_loaded_filename, :pass_args, :run_state,
|
539
|
+
:p_all_arguments, :p_options_parsed, :p_params, :p_rest
|
484
540
|
|
485
541
|
extend HashDelegatorSelf
|
486
542
|
include CompactionHelpers
|
@@ -501,6 +557,11 @@ module MarkdownExec
|
|
501
557
|
|
502
558
|
@process_mutex = Mutex.new
|
503
559
|
@process_cv = ConditionVariable.new
|
560
|
+
|
561
|
+
@p_all_arguments = []
|
562
|
+
@p_options_parsed = []
|
563
|
+
@p_params = {}
|
564
|
+
@p_rest = []
|
504
565
|
end
|
505
566
|
|
506
567
|
# private
|
@@ -513,6 +574,26 @@ module MarkdownExec
|
|
513
574
|
# @delegate_object[key] = value
|
514
575
|
# end
|
515
576
|
|
577
|
+
##
|
578
|
+
# Returns the absolute path of the given file path.
|
579
|
+
# If the provided path is already absolute, it returns it as is.
|
580
|
+
# Otherwise, it prefixes the path with the current working directory.
|
581
|
+
#
|
582
|
+
# @param file_path [String] The file path to process
|
583
|
+
# @return [String] The absolute path
|
584
|
+
#
|
585
|
+
# Example usage:
|
586
|
+
# absolute_path('/absolute/path/to/file.txt') # => '/absolute/path/to/file.txt'
|
587
|
+
# absolute_path('relative/path/to/file.txt') # => '/current/working/directory/relative/path/to/file.txt'
|
588
|
+
#
|
589
|
+
def absolute_path(file_path)
|
590
|
+
if File.absolute_path?(file_path)
|
591
|
+
file_path
|
592
|
+
else
|
593
|
+
File.join(Dir.getwd, file_path)
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
516
597
|
# Modifies the provided menu blocks array by adding 'Back' and 'Exit' options,
|
517
598
|
# along with initial and final dividers, based on the delegate object's configuration.
|
518
599
|
#
|
@@ -533,7 +614,8 @@ module MarkdownExec
|
|
533
614
|
add_exit_option(menu_blocks: menu_blocks)
|
534
615
|
end
|
535
616
|
|
536
|
-
|
617
|
+
append_divider(menu_blocks: menu_blocks, position: :initial)
|
618
|
+
append_divider(menu_blocks: menu_blocks, position: :final)
|
537
619
|
end
|
538
620
|
|
539
621
|
private
|
@@ -542,11 +624,6 @@ module MarkdownExec
|
|
542
624
|
append_chrome_block(menu_blocks: menu_blocks, menu_state: MenuState::BACK)
|
543
625
|
end
|
544
626
|
|
545
|
-
def add_dividers(menu_blocks:)
|
546
|
-
append_divider(menu_blocks: menu_blocks, position: :initial)
|
547
|
-
append_divider(menu_blocks: menu_blocks, position: :final)
|
548
|
-
end
|
549
|
-
|
550
627
|
def add_exit_option(menu_blocks:)
|
551
628
|
append_chrome_block(menu_blocks: menu_blocks, menu_state: MenuState::EXIT)
|
552
629
|
end
|
@@ -599,6 +676,7 @@ module MarkdownExec
|
|
599
676
|
dname: HashDelegator.new(@delegate_object).string_send_color(
|
600
677
|
formatted_name, :menu_chrome_color
|
601
678
|
),
|
679
|
+
nickname: formatted_name,
|
602
680
|
oname: formatted_name
|
603
681
|
)
|
604
682
|
|
@@ -728,6 +806,9 @@ module MarkdownExec
|
|
728
806
|
# 2024-08-04 match oname for long block names
|
729
807
|
# 2024-08-04 match nickname for long block names
|
730
808
|
block_name == item.pub_name || block_name == item.nickname || block_name == item.oname
|
809
|
+
end || @dml_menu_blocks.find do |item|
|
810
|
+
# 2024-08-22 search in menu blocks to allow matching of automatic chrome with nickname
|
811
|
+
block_name == item.pub_name || block_name == item.nickname || block_name == item.oname
|
731
812
|
end
|
732
813
|
end
|
733
814
|
|
@@ -814,7 +895,7 @@ module MarkdownExec
|
|
814
895
|
runtime_exception(:runtime_exception_error_level,
|
815
896
|
'unmet_dependencies, flag: runtime_exception_error_level',
|
816
897
|
required[:unmet_dependencies])
|
817
|
-
elsif
|
898
|
+
elsif @delegate_object[:dump_dependencies]
|
818
899
|
warn format_and_highlight_dependencies(dependencies,
|
819
900
|
highlight: [@delegate_object[:block_name]])
|
820
901
|
end
|
@@ -898,16 +979,20 @@ module MarkdownExec
|
|
898
979
|
# @param selected [Hash] The selected item from the menu to be executed.
|
899
980
|
# @return [LoadFileLinkState] An object indicating whether to load the next block or reuse the current one.
|
900
981
|
def compile_execute_and_trigger_reuse(mdoc:, selected:, block_source:,
|
901
|
-
link_state:
|
902
|
-
required_lines = collect_required_code_lines(
|
903
|
-
|
982
|
+
link_state:)
|
983
|
+
required_lines = collect_required_code_lines(
|
984
|
+
mdoc: mdoc, selected: selected,
|
985
|
+
link_state: link_state, block_source: block_source
|
986
|
+
)
|
904
987
|
output_or_approval = @delegate_object[:output_script] || @delegate_object[:user_must_approve]
|
905
988
|
if output_or_approval
|
906
989
|
display_required_code(required_lines: required_lines)
|
907
990
|
end
|
908
991
|
allow_execution = if @delegate_object[:user_must_approve]
|
909
|
-
prompt_for_user_approval(
|
910
|
-
|
992
|
+
prompt_for_user_approval(
|
993
|
+
required_lines: required_lines,
|
994
|
+
selected: selected
|
995
|
+
)
|
911
996
|
else
|
912
997
|
true
|
913
998
|
end
|
@@ -918,7 +1003,6 @@ module MarkdownExec
|
|
918
1003
|
end
|
919
1004
|
|
920
1005
|
link_state.block_name = nil
|
921
|
-
LoadFileLinkState.new(LoadFile::REUSE, link_state)
|
922
1006
|
end
|
923
1007
|
|
924
1008
|
# Check if the expression contains wildcard characters
|
@@ -1136,348 +1220,39 @@ module MarkdownExec
|
|
1136
1220
|
@delegate_object[:menu_divider_format].present? && @delegate_object[divider_key].present?
|
1137
1221
|
end
|
1138
1222
|
|
1139
|
-
def
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1223
|
+
def dml_menu_append_chrome_item(
|
1224
|
+
name, count, type, menu_state: MenuState::LOAD,
|
1225
|
+
always_create: true, always_enable: true
|
1226
|
+
)
|
1227
|
+
raise unless name.present?
|
1228
|
+
raise if @dml_menu_blocks.nil?
|
1145
1229
|
|
1146
|
-
|
1147
|
-
#
|
1148
|
-
# This method allows the user to interactively select a code block from a
|
1149
|
-
# Markdown document, obtain approval, and execute the chosen block of code.
|
1150
|
-
#
|
1151
|
-
# @return [Nil] Returns nil if no code block is selected or an error occurs.
|
1152
|
-
def document_inpseq
|
1153
|
-
@menu_base_options = @delegate_object
|
1154
|
-
@dml_link_state = LinkState.new(
|
1155
|
-
block_name: @delegate_object[:block_name],
|
1156
|
-
document_filename: @delegate_object[:filename]
|
1157
|
-
)
|
1158
|
-
@run_state.source.block_name_from_cli = @dml_link_state.block_name.present?
|
1159
|
-
@cli_block_name = @dml_link_state.block_name
|
1160
|
-
@dml_now_using_cli = @run_state.source.block_name_from_cli
|
1161
|
-
@dml_menu_default_dname = nil
|
1162
|
-
@dml_block_state = SelectedBlockMenuState.new
|
1163
|
-
@doc_saved_lines_files = []
|
1230
|
+
item = @dml_menu_blocks.find { |block| block.oname == name }
|
1164
1231
|
|
1165
|
-
|
1232
|
+
# create menu item when it is needed (count > 0)
|
1166
1233
|
#
|
1167
|
-
if
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
end.flatten(1)
|
1172
|
-
|
1173
|
-
inherited_block_names = []
|
1174
|
-
inherited_dependencies = {}
|
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
|
-
}
|
1190
|
-
item_back = fdo.call(:menu_option_back_name)
|
1191
|
-
item_edit = fdo.call(:menu_option_edit_name)
|
1192
|
-
item_history = fdo.call(:menu_option_history_name)
|
1193
|
-
item_load = fdo.call(:menu_option_load_name)
|
1194
|
-
item_save = fdo.call(:menu_option_save_name)
|
1195
|
-
item_shell = fdo.call(:menu_option_shell_name)
|
1196
|
-
item_view = fdo.call(:menu_option_view_name)
|
1197
|
-
|
1198
|
-
@run_state.batch_random = Random.new.rand
|
1199
|
-
@run_state.batch_index = 0
|
1200
|
-
|
1201
|
-
@run_state.files = StreamsOut.new
|
1202
|
-
|
1203
|
-
InputSequencer.new(
|
1204
|
-
@delegate_object[:filename],
|
1205
|
-
@delegate_object[:input_cli_rest]
|
1206
|
-
).run do |msg, data|
|
1207
|
-
# &bt msg
|
1208
|
-
case msg
|
1209
|
-
when :parse_document # once for each menu
|
1210
|
-
# puts "@ - parse document #{data}"
|
1211
|
-
inpseq_parse_document(data)
|
1212
|
-
|
1213
|
-
if @delegate_object[:menu_for_history]
|
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
|
1219
|
-
end
|
1220
|
-
end
|
1221
|
-
|
1222
|
-
if @delegate_object[:menu_for_saved_lines] && @delegate_object[:document_saved_lines_glob].present?
|
1223
|
-
|
1224
|
-
sf = document_name_in_glob_as_file_name(
|
1225
|
-
@dml_link_state.document_filename,
|
1226
|
-
@delegate_object[:document_saved_lines_glob]
|
1227
|
-
)
|
1228
|
-
files = sf ? Dir.glob(sf) : []
|
1229
|
-
@doc_saved_lines_files = files.count.positive? ? files : []
|
1230
|
-
|
1231
|
-
lines_count = @dml_link_state.inherited_lines_count
|
1232
|
-
|
1233
|
-
# add menu items (glob, load, save) and enable selectively
|
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)
|
1260
|
-
end
|
1261
|
-
|
1262
|
-
when :display_menu
|
1263
|
-
# warn "@ - display menu:"
|
1264
|
-
# ii_display_menu
|
1265
|
-
@dml_block_state = SelectedBlockMenuState.new
|
1266
|
-
@delegate_object[:block_name] = nil
|
1267
|
-
|
1268
|
-
when :user_choice
|
1269
|
-
if @dml_link_state.block_name.present?
|
1270
|
-
# @prior_block_was_link = true
|
1271
|
-
@dml_block_state.block = blocks_find_by_block_name(@dml_blocks_in_file,
|
1272
|
-
@dml_link_state.block_name)
|
1273
|
-
@dml_link_state.block_name = nil
|
1274
|
-
else
|
1275
|
-
# puts "? - Select a block to execute (or type #{$texit} to exit):"
|
1276
|
-
break if inpseq_user_choice == :break # into @dml_block_state
|
1277
|
-
break if @dml_block_state.block.nil? # no block matched
|
1278
|
-
end
|
1279
|
-
# puts "! - Executing block: #{data}"
|
1280
|
-
@dml_block_state.block&.pub_name
|
1281
|
-
|
1282
|
-
when :execute_block
|
1283
|
-
case (block_name = data)
|
1284
|
-
when item_back.pub_name
|
1285
|
-
debounce_reset
|
1286
|
-
@menu_user_clicked_back_link = true
|
1287
|
-
load_file_link_state = pop_link_history_and_trigger_load
|
1288
|
-
@dml_link_state = load_file_link_state.link_state
|
1289
|
-
|
1290
|
-
InputSequencer.merge_link_state(
|
1291
|
-
@dml_link_state,
|
1292
|
-
InputSequencer.next_link_state(
|
1293
|
-
block_name: @dml_link_state.block_name,
|
1294
|
-
document_filename: @dml_link_state.document_filename,
|
1295
|
-
prior_block_was_link: true
|
1296
|
-
)
|
1297
|
-
)
|
1298
|
-
|
1299
|
-
when item_edit.pub_name
|
1300
|
-
debounce_reset
|
1301
|
-
edited = edit_text(@dml_link_state.inherited_lines_block)
|
1302
|
-
@dml_link_state.inherited_lines = edited.split("\n") if edited
|
1303
|
-
|
1304
|
-
return :break if pause_user_exit
|
1305
|
-
|
1306
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
1307
|
-
|
1308
|
-
when item_history.pub_name
|
1309
|
-
debounce_reset
|
1310
|
-
files = history_files(@dml_link_state)
|
1311
|
-
files_table_rows = files.map do |file|
|
1312
|
-
if Regexp.new(@delegate_object[:saved_asset_match]) =~ file
|
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
|
1330
|
-
else
|
1331
|
-
warn "Cannot parse name: #{file}"
|
1332
|
-
next
|
1333
|
-
end
|
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
|
1362
|
-
end
|
1363
|
-
|
1364
|
-
return :break if pause_user_exit
|
1365
|
-
|
1366
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
1367
|
-
|
1368
|
-
when item_load.pub_name
|
1369
|
-
debounce_reset
|
1370
|
-
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1371
|
-
@delegate_object[:document_saved_lines_glob])
|
1372
|
-
load_filespec = load_filespec_from_expression(sf)
|
1373
|
-
if load_filespec
|
1374
|
-
@dml_link_state.inherited_lines_append(
|
1375
|
-
File.readlines(load_filespec, chomp: true)
|
1376
|
-
)
|
1377
|
-
end
|
1378
|
-
|
1379
|
-
return :break if pause_user_exit
|
1380
|
-
|
1381
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
1382
|
-
|
1383
|
-
when item_save.pub_name
|
1384
|
-
debounce_reset
|
1385
|
-
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
1386
|
-
@delegate_object[:document_saved_lines_glob])
|
1387
|
-
save_filespec = save_filespec_from_expression(sf)
|
1388
|
-
if save_filespec && !write_file_with_directory_creation(
|
1389
|
-
save_filespec,
|
1390
|
-
HashDelegator.join_code_lines(@dml_link_state.inherited_lines)
|
1391
|
-
)
|
1392
|
-
return :break
|
1393
|
-
|
1394
|
-
end
|
1395
|
-
|
1396
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
1397
|
-
|
1398
|
-
when item_shell.pub_name
|
1399
|
-
debounce_reset
|
1400
|
-
loop do
|
1401
|
-
command = prompt_for_command(":MDE #{Time.now.strftime('%FT%TZ')}> ".bgreen)
|
1402
|
-
break if !command.present? || command == 'exit'
|
1403
|
-
|
1404
|
-
exit_status = execute_command_with_streams(
|
1405
|
-
[@delegate_object[:shell], '-c', command]
|
1406
|
-
)
|
1407
|
-
case exit_status
|
1408
|
-
when 0
|
1409
|
-
warn "#{'OK'.green} #{exit_status}"
|
1410
|
-
else
|
1411
|
-
warn "#{'ERR'.bred} #{exit_status}"
|
1412
|
-
end
|
1413
|
-
end
|
1414
|
-
|
1415
|
-
return :break if pause_user_exit
|
1416
|
-
|
1417
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
1418
|
-
|
1419
|
-
when item_view.pub_name
|
1420
|
-
debounce_reset
|
1421
|
-
warn @dml_link_state.inherited_lines_block
|
1422
|
-
|
1423
|
-
return :break if pause_user_exit
|
1424
|
-
|
1425
|
-
InputSequencer.next_link_state(prior_block_was_link: true)
|
1426
|
-
|
1427
|
-
else
|
1428
|
-
@dml_block_state = block_state_for_name_from_cli(block_name)
|
1429
|
-
if @dml_block_state.block && @dml_block_state.block.shell == BlockType::OPTS
|
1430
|
-
debounce_reset
|
1431
|
-
link_state = LinkState.new
|
1432
|
-
options_state = read_show_options_and_trigger_reuse(
|
1433
|
-
link_state: link_state,
|
1434
|
-
mdoc: @dml_mdoc,
|
1435
|
-
selected: @dml_block_state.block
|
1436
|
-
)
|
1437
|
-
|
1438
|
-
update_menu_base(options_state.options)
|
1439
|
-
options_state.load_file_link_state.link_state
|
1440
|
-
else
|
1441
|
-
inpseq_execute_block(block_name)
|
1234
|
+
if item.nil? && (always_create || count.positive?)
|
1235
|
+
item = append_chrome_block(menu_blocks: @dml_menu_blocks,
|
1236
|
+
menu_state: menu_state)
|
1237
|
+
end
|
1442
1238
|
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
end
|
1239
|
+
# update item if it exists
|
1240
|
+
#
|
1241
|
+
return unless item
|
1447
1242
|
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
was_using_cli: @dml_now_using_cli
|
1456
|
-
)
|
1457
|
-
|
1458
|
-
if !@dml_block_state.source.block_name_from_ui && cli_break
|
1459
|
-
# &bsp '!block_name_from_ui + cli_break -> break'
|
1460
|
-
return :break
|
1461
|
-
end
|
1243
|
+
item.dname = type.present? ? "#{name} (#{count} #{type})" : name
|
1244
|
+
if always_enable || count.positive?
|
1245
|
+
item.delete(:disabled)
|
1246
|
+
else
|
1247
|
+
item[:disabled] = ''
|
1248
|
+
end
|
1249
|
+
end
|
1462
1250
|
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
)
|
1467
|
-
end
|
1468
|
-
end
|
1251
|
+
def do_save_execution_output
|
1252
|
+
return unless @delegate_object[:save_execution_output]
|
1253
|
+
return if @run_state.in_own_window
|
1469
1254
|
|
1470
|
-
|
1471
|
-
data == $texit
|
1472
|
-
when :stay?
|
1473
|
-
data == $stay
|
1474
|
-
else
|
1475
|
-
raise "Invalid message: #{msg}"
|
1476
|
-
end
|
1477
|
-
end
|
1478
|
-
rescue StandardError
|
1479
|
-
HashDelegator.error_handler('document_inpseq',
|
1480
|
-
{ abort: true })
|
1255
|
+
@run_state.files.write_execution_output_to_file(@delegate_object[:logged_stdout_filespec])
|
1481
1256
|
end
|
1482
1257
|
|
1483
1258
|
# remove leading "./"
|
@@ -1492,9 +1267,9 @@ module MarkdownExec
|
|
1492
1267
|
'_') })
|
1493
1268
|
end
|
1494
1269
|
|
1495
|
-
def dump_and_warn_block_state(selected:)
|
1270
|
+
def dump_and_warn_block_state(name:, selected:)
|
1496
1271
|
if selected.nil?
|
1497
|
-
Exceptions.warn_format("Block not found -- name: #{
|
1272
|
+
Exceptions.warn_format("Block not found -- name: #{name}",
|
1498
1273
|
{ abort: true })
|
1499
1274
|
end
|
1500
1275
|
|
@@ -1591,8 +1366,9 @@ module MarkdownExec
|
|
1591
1366
|
result_text
|
1592
1367
|
end
|
1593
1368
|
|
1594
|
-
def
|
1595
|
-
|
1369
|
+
def execute_block_for_state_and_name(selected:, mdoc:, link_state:,
|
1370
|
+
block_source: {})
|
1371
|
+
lfls = execute_block_by_type_for_lfls(
|
1596
1372
|
selected: selected,
|
1597
1373
|
mdoc: mdoc,
|
1598
1374
|
link_state: link_state,
|
@@ -1601,8 +1377,26 @@ module MarkdownExec
|
|
1601
1377
|
|
1602
1378
|
# if the same menu is being displayed, collect the display name of the selected menu item for use as the default item
|
1603
1379
|
[lfls.link_state,
|
1604
|
-
lfls.load_file == LoadFile::LOAD ? nil : selected.dname
|
1605
|
-
|
1380
|
+
lfls.load_file == LoadFile::LOAD ? nil : selected.dname,
|
1381
|
+
# 2024-08-22 true to quit
|
1382
|
+
lfls.load_file == LoadFile::EXIT]
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
def execute_block_in_state(block_name)
|
1386
|
+
@dml_block_state = block_state_for_name_from_cli(block_name)
|
1387
|
+
dump_and_warn_block_state(name: block_name,
|
1388
|
+
selected: @dml_block_state.block)
|
1389
|
+
@dml_link_state, @dml_menu_default_dname, quit =
|
1390
|
+
execute_block_for_state_and_name(
|
1391
|
+
selected: @dml_block_state.block,
|
1392
|
+
mdoc: @dml_mdoc,
|
1393
|
+
link_state: @dml_link_state,
|
1394
|
+
block_source: {
|
1395
|
+
document_filename: @delegate_object[:filename],
|
1396
|
+
time_now_date: Time.now.utc.strftime(@delegate_object[:shell_code_label_time_format])
|
1397
|
+
}
|
1398
|
+
)
|
1399
|
+
:break if quit
|
1606
1400
|
end
|
1607
1401
|
|
1608
1402
|
# Executes a given command and processes its input, output, and error streams.
|
@@ -1655,6 +1449,82 @@ module MarkdownExec
|
|
1655
1449
|
exit_status
|
1656
1450
|
end
|
1657
1451
|
|
1452
|
+
def execute_history_select(
|
1453
|
+
files_table_rows,
|
1454
|
+
exit_prompt: @delegate_object[:prompt_filespec_back],
|
1455
|
+
pause_refresh: false,
|
1456
|
+
stream:
|
1457
|
+
)
|
1458
|
+
# repeat select+display until user exits
|
1459
|
+
|
1460
|
+
pause_now = false
|
1461
|
+
row_attrib = :row
|
1462
|
+
loop do
|
1463
|
+
if pause_now
|
1464
|
+
break if prompt_select_continue == MenuState::EXIT
|
1465
|
+
end
|
1466
|
+
|
1467
|
+
# menu with Back and Facet options at top
|
1468
|
+
case (name = prompt_select_code_filename(
|
1469
|
+
[exit_prompt,
|
1470
|
+
@delegate_object[:prompt_filespec_facet]] +
|
1471
|
+
files_table_rows.map(&row_attrib),
|
1472
|
+
string: @delegate_object[:prompt_select_history_file],
|
1473
|
+
color_sym: :prompt_color_after_script_execution
|
1474
|
+
))
|
1475
|
+
when exit_prompt
|
1476
|
+
break
|
1477
|
+
when @delegate_object[:prompt_filespec_facet]
|
1478
|
+
row_attrib = row_attrib == :row ? :file : :row
|
1479
|
+
pause_now = false
|
1480
|
+
else
|
1481
|
+
file = files_table_rows.select { |ftr| ftr.row == name }&.first
|
1482
|
+
info = file_info(file.file)
|
1483
|
+
stream.puts "#{file.file} - #{info[:lines]} lines / " \
|
1484
|
+
"#{info[:size]} bytes"
|
1485
|
+
stream.puts(
|
1486
|
+
File.readlines(file.file,
|
1487
|
+
chomp: false).map.with_index do |line, ind|
|
1488
|
+
format(' %s. %s',
|
1489
|
+
AnsiString.new(format('% 4d', ind + 1)).send(:violet), line)
|
1490
|
+
end
|
1491
|
+
)
|
1492
|
+
pause_now = pause_refresh
|
1493
|
+
end
|
1494
|
+
end
|
1495
|
+
end
|
1496
|
+
|
1497
|
+
def execute_inherited_save
|
1498
|
+
save_filespec = save_filespec_from_expression(
|
1499
|
+
document_name_in_glob_as_file_name(
|
1500
|
+
@dml_link_state.document_filename,
|
1501
|
+
@delegate_object[:document_saved_lines_glob]
|
1502
|
+
)
|
1503
|
+
)
|
1504
|
+
if save_filespec && !write_file_with_directory_creation(
|
1505
|
+
save_filespec,
|
1506
|
+
HashDelegator.join_code_lines(@dml_link_state.inherited_lines)
|
1507
|
+
)
|
1508
|
+
:break
|
1509
|
+
end
|
1510
|
+
end
|
1511
|
+
|
1512
|
+
def execute_navigate_back
|
1513
|
+
@menu_user_clicked_back_link = true
|
1514
|
+
|
1515
|
+
keep_code = @dml_link_state.keep_code
|
1516
|
+
inherited_lines = keep_code ? @dml_link_state.inherited_lines_block : nil
|
1517
|
+
|
1518
|
+
@dml_link_state = pop_link_history_new_state
|
1519
|
+
|
1520
|
+
{
|
1521
|
+
block_name: @dml_link_state.block_name,
|
1522
|
+
document_filename: @dml_link_state.document_filename,
|
1523
|
+
inherited_lines: inherited_lines,
|
1524
|
+
keep_code: keep_code
|
1525
|
+
}
|
1526
|
+
end
|
1527
|
+
|
1658
1528
|
# Executes a block of code that has been approved for execution.
|
1659
1529
|
# It sets the script block name, writes command files if required, and handles the execution
|
1660
1530
|
# including output formatting and summarization.
|
@@ -1682,8 +1552,8 @@ module MarkdownExec
|
|
1682
1552
|
# @param opts [Hash] Options hash containing configuration settings.
|
1683
1553
|
# @param mdoc [YourMDocClass] An instance of the MDoc class.
|
1684
1554
|
#
|
1685
|
-
def
|
1686
|
-
|
1555
|
+
def execute_block_by_type_for_lfls(selected:, mdoc:, block_source:,
|
1556
|
+
link_state: LinkState.new)
|
1687
1557
|
if selected.shell == BlockType::LINK
|
1688
1558
|
debounce_reset
|
1689
1559
|
push_link_history_and_trigger_load(link_block_body: selected.body,
|
@@ -1692,9 +1562,18 @@ module MarkdownExec
|
|
1692
1562
|
link_state: link_state,
|
1693
1563
|
block_source: block_source)
|
1694
1564
|
|
1565
|
+
# from CLI
|
1566
|
+
elsif selected.nickname == @delegate_object[:menu_option_exit_name][:line]
|
1567
|
+
debounce_reset
|
1568
|
+
LoadFileLinkState.new(LoadFile::EXIT, link_state)
|
1569
|
+
|
1695
1570
|
elsif @menu_user_clicked_back_link
|
1696
1571
|
debounce_reset
|
1697
|
-
|
1572
|
+
# pop_link_history_new_state
|
1573
|
+
LoadFileLinkState.new(
|
1574
|
+
LoadFile::LOAD,
|
1575
|
+
pop_link_history_new_state
|
1576
|
+
)
|
1698
1577
|
|
1699
1578
|
elsif selected.shell == BlockType::OPTS
|
1700
1579
|
debounce_reset
|
@@ -1730,6 +1609,7 @@ module MarkdownExec
|
|
1730
1609
|
selected: selected,
|
1731
1610
|
link_state: link_state,
|
1732
1611
|
block_source: block_source)
|
1612
|
+
LoadFileLinkState.new(LoadFile::REUSE, link_state)
|
1733
1613
|
|
1734
1614
|
else
|
1735
1615
|
LoadFileLinkState.new(LoadFile::REUSE, link_state)
|
@@ -1812,6 +1692,27 @@ module MarkdownExec
|
|
1812
1692
|
expr.include?('%{') ? format_expression(expr) : expr
|
1813
1693
|
end
|
1814
1694
|
|
1695
|
+
def fout_execution_report
|
1696
|
+
@fout.fout fetch_color(data_sym: :execution_report_preview_head,
|
1697
|
+
color_sym: :execution_report_preview_frame_color)
|
1698
|
+
[
|
1699
|
+
['Block', @run_state.script_block_name],
|
1700
|
+
['Command', ([MarkdownExec::BIN_NAME, @delegate_object[:filename]] +
|
1701
|
+
(@run_state.link_history.map { |item|
|
1702
|
+
item[:block_name]
|
1703
|
+
}) +
|
1704
|
+
[@run_state.script_block_name]).join(' ')],
|
1705
|
+
['Script', @run_state.saved_filespec],
|
1706
|
+
['StdOut', @delegate_object[:logged_stdout_filespec]]
|
1707
|
+
].each do |label, value|
|
1708
|
+
next unless value
|
1709
|
+
|
1710
|
+
output_labeled_value(label, value, DISPLAY_LEVEL_ADMIN)
|
1711
|
+
end
|
1712
|
+
@fout.fout fetch_color(data_sym: :execution_report_preview_tail,
|
1713
|
+
color_sym: :execution_report_preview_frame_color)
|
1714
|
+
end
|
1715
|
+
|
1815
1716
|
def generate_temp_filename(ext = '.sh')
|
1816
1717
|
filename = begin
|
1817
1718
|
Dir::Tmpname.make_tmpname(['x', ext], nil)
|
@@ -1929,45 +1830,6 @@ module MarkdownExec
|
|
1929
1830
|
}
|
1930
1831
|
end
|
1931
1832
|
|
1932
|
-
def inpseq_execute_block(block_name)
|
1933
|
-
@dml_block_state = block_state_for_name_from_cli(block_name)
|
1934
|
-
dump_and_warn_block_state(selected: @dml_block_state.block)
|
1935
|
-
@dml_link_state, @dml_menu_default_dname =
|
1936
|
-
exec_bash_next_state(
|
1937
|
-
selected: @dml_block_state.block,
|
1938
|
-
mdoc: @dml_mdoc,
|
1939
|
-
link_state: @dml_link_state,
|
1940
|
-
block_source: {
|
1941
|
-
document_filename: @delegate_object[:filename],
|
1942
|
-
time_now_date: Time.now.utc.strftime(@delegate_object[:shell_code_label_time_format])
|
1943
|
-
}
|
1944
|
-
)
|
1945
|
-
end
|
1946
|
-
|
1947
|
-
def inpseq_parse_document(_document_filename)
|
1948
|
-
@run_state.batch_index += 1
|
1949
|
-
@run_state.in_own_window = false
|
1950
|
-
|
1951
|
-
# &bsp 'loop', block_name_from_cli, @cli_block_name
|
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,
|
1954
|
-
now_using_cli: @dml_now_using_cli,
|
1955
|
-
link_state: @dml_link_state)
|
1956
|
-
end
|
1957
|
-
|
1958
|
-
def inpseq_user_choice
|
1959
|
-
@dml_block_state = load_cli_or_user_selected_block(all_blocks: @dml_blocks_in_file,
|
1960
|
-
menu_blocks: @dml_menu_blocks,
|
1961
|
-
default: @dml_menu_default_dname)
|
1962
|
-
# &bsp '@run_state.source.block_name_from_cli:',@run_state.source.block_name_from_cli
|
1963
|
-
if !@dml_block_state
|
1964
|
-
HashDelegator.error_handler('block_state missing', { abort: true })
|
1965
|
-
elsif @dml_block_state.state == MenuState::EXIT
|
1966
|
-
# &bsp 'load_cli_or_user_selected_block -> break'
|
1967
|
-
:break
|
1968
|
-
end
|
1969
|
-
end
|
1970
|
-
|
1971
1833
|
# Iterates through blocks in a file, applying the provided block to each line.
|
1972
1834
|
# The iteration only occurs if the file exists.
|
1973
1835
|
# @yield [Symbol] :filter Yields to obtain selected messages for processing.
|
@@ -1975,11 +1837,11 @@ module MarkdownExec
|
|
1975
1837
|
return unless check_file_existence(@delegate_object[:filename])
|
1976
1838
|
|
1977
1839
|
state = initial_state
|
1978
|
-
|
1840
|
+
selected_types = yield :filter
|
1979
1841
|
cfile.readlines(@delegate_object[:filename],
|
1980
1842
|
import_paths: @delegate_object[:import_paths]&.split(':')).each do |nested_line|
|
1981
1843
|
if nested_line
|
1982
|
-
update_line_and_block_state(nested_line, state,
|
1844
|
+
update_line_and_block_state(nested_line, state, selected_types,
|
1983
1845
|
&block)
|
1984
1846
|
end
|
1985
1847
|
end
|
@@ -2027,8 +1889,9 @@ module MarkdownExec
|
|
2027
1889
|
label_format_above = @delegate_object[:shell_code_label_format_above]
|
2028
1890
|
label_format_below = @delegate_object[:shell_code_label_format_below]
|
2029
1891
|
|
2030
|
-
[label_format_above &&
|
2031
|
-
|
1892
|
+
[label_format_above.present? &&
|
1893
|
+
format(label_format_above,
|
1894
|
+
block_source.merge({ block_name: selected.pub_name }))] +
|
2032
1895
|
output_lines.map do |line|
|
2033
1896
|
re = Regexp.new(link_block_data.fetch('pattern', '(?<line>.*)'))
|
2034
1897
|
next unless re =~ line
|
@@ -2037,14 +1900,17 @@ module MarkdownExec
|
|
2037
1900
|
link_block_data.fetch('format',
|
2038
1901
|
'%{line}'))
|
2039
1902
|
end.compact +
|
2040
|
-
[label_format_below &&
|
2041
|
-
|
1903
|
+
[label_format_below.present? &&
|
1904
|
+
format(label_format_below,
|
1905
|
+
block_source.merge({ block_name: selected.pub_name }))]
|
2042
1906
|
end
|
2043
1907
|
|
2044
1908
|
def link_history_push_and_next(
|
2045
1909
|
curr_block_name:, curr_document_filename:,
|
2046
1910
|
inherited_block_names:, inherited_dependencies:, inherited_lines:,
|
1911
|
+
keep_code:,
|
2047
1912
|
next_block_name:, next_document_filename:,
|
1913
|
+
next_keep_code:,
|
2048
1914
|
next_load_file:
|
2049
1915
|
)
|
2050
1916
|
@link_history.push(
|
@@ -2053,7 +1919,8 @@ module MarkdownExec
|
|
2053
1919
|
document_filename: curr_document_filename,
|
2054
1920
|
inherited_block_names: inherited_block_names,
|
2055
1921
|
inherited_dependencies: inherited_dependencies,
|
2056
|
-
inherited_lines: inherited_lines
|
1922
|
+
inherited_lines: inherited_lines,
|
1923
|
+
keep_code: keep_code
|
2057
1924
|
)
|
2058
1925
|
)
|
2059
1926
|
LoadFileLinkState.new(
|
@@ -2063,7 +1930,8 @@ module MarkdownExec
|
|
2063
1930
|
document_filename: next_document_filename,
|
2064
1931
|
inherited_block_names: inherited_block_names,
|
2065
1932
|
inherited_dependencies: inherited_dependencies,
|
2066
|
-
inherited_lines: inherited_lines
|
1933
|
+
inherited_lines: inherited_lines,
|
1934
|
+
keep_code: next_keep_code
|
2067
1935
|
)
|
2068
1936
|
)
|
2069
1937
|
end
|
@@ -2119,8 +1987,6 @@ module MarkdownExec
|
|
2119
1987
|
end
|
2120
1988
|
|
2121
1989
|
SelectedBlockMenuState.new(block, source, state)
|
2122
|
-
rescue StandardError
|
2123
|
-
HashDelegator.error_handler('load_cli_or_user_selected_block')
|
2124
1990
|
end
|
2125
1991
|
|
2126
1992
|
# format + glob + select for file in load block
|
@@ -2161,6 +2027,23 @@ module MarkdownExec
|
|
2161
2027
|
end
|
2162
2028
|
end
|
2163
2029
|
|
2030
|
+
def manage_cli_selection_state(block_name_from_cli:, now_using_cli:,
|
2031
|
+
link_state:)
|
2032
|
+
if block_name_from_cli && @cli_block_name == @menu_base_options[:menu_persist_block_name]
|
2033
|
+
# &bsp 'pause cli control, allow user to select block'
|
2034
|
+
block_name_from_cli = false
|
2035
|
+
now_using_cli = false
|
2036
|
+
@menu_base_options[:block_name] =
|
2037
|
+
@delegate_object[:block_name] = \
|
2038
|
+
link_state.block_name =
|
2039
|
+
@cli_block_name = nil
|
2040
|
+
end
|
2041
|
+
|
2042
|
+
@delegate_object = @menu_base_options.dup
|
2043
|
+
@menu_user_clicked_back_link = false
|
2044
|
+
[block_name_from_cli, now_using_cli]
|
2045
|
+
end
|
2046
|
+
|
2164
2047
|
def mdoc_and_blocks_from_nested_files
|
2165
2048
|
menu_blocks = blocks_from_nested_files
|
2166
2049
|
mdoc = MDoc.new(menu_blocks) do |nopts|
|
@@ -2184,6 +2067,7 @@ module MarkdownExec
|
|
2184
2067
|
add_menu_chrome_blocks!(menu_blocks: menu_blocks, link_state: link_state)
|
2185
2068
|
### compress empty lines
|
2186
2069
|
HashDelegator.delete_consecutive_blank_lines!(menu_blocks)
|
2070
|
+
HashDelegator.tables_into_columns!(menu_blocks, @delegate_object)
|
2187
2071
|
[all_blocks, menu_blocks, mdoc] # &br
|
2188
2072
|
end
|
2189
2073
|
|
@@ -2240,48 +2124,6 @@ module MarkdownExec
|
|
2240
2124
|
end
|
2241
2125
|
end
|
2242
2126
|
|
2243
|
-
def menu_enable_option(name, count, type, menu_state: MenuState::LOAD)
|
2244
|
-
raise unless name.present?
|
2245
|
-
raise if @dml_menu_blocks.nil?
|
2246
|
-
|
2247
|
-
item = @dml_menu_blocks.find { |block| block.oname == name }
|
2248
|
-
|
2249
|
-
# create menu item when it is needed (count > 0)
|
2250
|
-
#
|
2251
|
-
if item.nil? && count.positive?
|
2252
|
-
item = append_chrome_block(menu_blocks: @dml_menu_blocks,
|
2253
|
-
menu_state: menu_state)
|
2254
|
-
end
|
2255
|
-
|
2256
|
-
# update item if it exists
|
2257
|
-
#
|
2258
|
-
return unless item
|
2259
|
-
|
2260
|
-
item.dname = type.present? ? "#{name} (#{count} #{type})" : name
|
2261
|
-
if count.positive?
|
2262
|
-
item.delete(:disabled)
|
2263
|
-
else
|
2264
|
-
item[:disabled] = ''
|
2265
|
-
end
|
2266
|
-
end
|
2267
|
-
|
2268
|
-
def manage_cli_selection_state(block_name_from_cli:, now_using_cli:,
|
2269
|
-
link_state:)
|
2270
|
-
if block_name_from_cli && @cli_block_name == @menu_base_options[:menu_persist_block_name]
|
2271
|
-
# &bsp 'pause cli control, allow user to select block'
|
2272
|
-
block_name_from_cli = false
|
2273
|
-
now_using_cli = false
|
2274
|
-
@menu_base_options[:block_name] =
|
2275
|
-
@delegate_object[:block_name] = \
|
2276
|
-
link_state.block_name =
|
2277
|
-
@cli_block_name = nil
|
2278
|
-
end
|
2279
|
-
|
2280
|
-
@delegate_object = @menu_base_options.dup
|
2281
|
-
@menu_user_clicked_back_link = false
|
2282
|
-
[block_name_from_cli, now_using_cli]
|
2283
|
-
end
|
2284
|
-
|
2285
2127
|
# If a method is missing, treat it as a key for the @delegate_object.
|
2286
2128
|
def method_missing(method_name, *args, &block)
|
2287
2129
|
if @delegate_object.respond_to?(method_name)
|
@@ -2309,8 +2151,10 @@ module MarkdownExec
|
|
2309
2151
|
inherited_block_names: ((link_state&.inherited_block_names || []) + block_names).sort.uniq,
|
2310
2152
|
inherited_dependencies: (link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
2311
2153
|
inherited_lines: HashDelegator.code_merge(code_lines),
|
2154
|
+
keep_code: link_state&.keep_code,
|
2312
2155
|
next_block_name: '',
|
2313
2156
|
next_document_filename: @delegate_object[:filename],
|
2157
|
+
next_keep_code: false,
|
2314
2158
|
next_load_file: LoadFile::REUSE
|
2315
2159
|
)
|
2316
2160
|
end
|
@@ -2321,27 +2165,6 @@ module MarkdownExec
|
|
2321
2165
|
@fout.fout formatted_string
|
2322
2166
|
end
|
2323
2167
|
|
2324
|
-
def fout_execution_report
|
2325
|
-
@fout.fout fetch_color(data_sym: :execution_report_preview_head,
|
2326
|
-
color_sym: :execution_report_preview_frame_color)
|
2327
|
-
[
|
2328
|
-
['Block', @run_state.script_block_name],
|
2329
|
-
['Command', ([MarkdownExec::BIN_NAME, @delegate_object[:filename]] +
|
2330
|
-
(@run_state.link_history.map { |item|
|
2331
|
-
item[:block_name]
|
2332
|
-
}) +
|
2333
|
-
[@run_state.script_block_name]).join(' ')],
|
2334
|
-
['Script', @run_state.saved_filespec],
|
2335
|
-
['StdOut', @delegate_object[:logged_stdout_filespec]]
|
2336
|
-
].each do |label, value|
|
2337
|
-
next unless value
|
2338
|
-
|
2339
|
-
output_labeled_value(label, value, DISPLAY_LEVEL_ADMIN)
|
2340
|
-
end
|
2341
|
-
@fout.fout fetch_color(data_sym: :execution_report_preview_tail,
|
2342
|
-
color_sym: :execution_report_preview_frame_color)
|
2343
|
-
end
|
2344
|
-
|
2345
2168
|
def output_execution_summary
|
2346
2169
|
return unless @delegate_object[:output_execution_summary]
|
2347
2170
|
|
@@ -2401,8 +2224,10 @@ module MarkdownExec
|
|
2401
2224
|
(link_state&.inherited_dependencies || {}).merge(dependencies || {}), ### merge, not replace, key data
|
2402
2225
|
inherited_lines:
|
2403
2226
|
HashDelegator.code_merge(link_state&.inherited_lines, code_lines),
|
2227
|
+
keep_code: link_state&.keep_code,
|
2404
2228
|
next_block_name: next_block_name,
|
2405
2229
|
next_document_filename: @delegate_object[:filename], # not next_document_filename
|
2230
|
+
next_keep_code: false,
|
2406
2231
|
next_load_file: LoadFile::REUSE # not next_document_filename == @delegate_object[:filename] ? LoadFile::REUSE : LoadFile::LOAD
|
2407
2232
|
)
|
2408
2233
|
# LoadFileLinkState.new(LoadFile::REUSE, link_state)
|
@@ -2410,20 +2235,17 @@ module MarkdownExec
|
|
2410
2235
|
end
|
2411
2236
|
|
2412
2237
|
# This method handles the back-link operation in the Markdown execution context.
|
2413
|
-
# It updates the history state
|
2238
|
+
# It updates the history state for the next block.
|
2414
2239
|
#
|
2415
|
-
# @return [
|
2416
|
-
def
|
2240
|
+
# @return [LinkState] An object indicating the state for the next block.
|
2241
|
+
def pop_link_history_new_state
|
2417
2242
|
pop = @link_history.pop
|
2418
2243
|
peek = @link_history.peek
|
2419
|
-
|
2420
|
-
|
2421
|
-
|
2422
|
-
|
2423
|
-
|
2424
|
-
inherited_dependencies: peek.inherited_dependencies,
|
2425
|
-
inherited_lines: peek.inherited_lines
|
2426
|
-
)
|
2244
|
+
LinkState.new(
|
2245
|
+
document_filename: pop.document_filename,
|
2246
|
+
inherited_block_names: peek.inherited_block_names,
|
2247
|
+
inherited_dependencies: peek.inherited_dependencies,
|
2248
|
+
inherited_lines: peek.inherited_lines
|
2427
2249
|
)
|
2428
2250
|
end
|
2429
2251
|
|
@@ -2532,8 +2354,6 @@ module MarkdownExec
|
|
2532
2354
|
|
2533
2355
|
@allowed_execution_block = @prior_execution_block
|
2534
2356
|
true
|
2535
|
-
rescue TTY::Reader::InputInterrupt
|
2536
|
-
exit 1
|
2537
2357
|
end
|
2538
2358
|
|
2539
2359
|
def prompt_for_command(prompt)
|
@@ -2602,8 +2422,6 @@ module MarkdownExec
|
|
2602
2422
|
end
|
2603
2423
|
|
2604
2424
|
sel == MenuOptions::YES
|
2605
|
-
rescue TTY::Reader::InputInterrupt
|
2606
|
-
exit 1
|
2607
2425
|
end
|
2608
2426
|
|
2609
2427
|
# public
|
@@ -2632,8 +2450,6 @@ module MarkdownExec
|
|
2632
2450
|
end
|
2633
2451
|
end
|
2634
2452
|
end
|
2635
|
-
rescue TTY::Reader::InputInterrupt
|
2636
|
-
exit 1
|
2637
2453
|
end
|
2638
2454
|
|
2639
2455
|
def prompt_select_continue(filter: true, quiet: true)
|
@@ -2647,8 +2463,6 @@ module MarkdownExec
|
|
2647
2463
|
menu.choice @delegate_object[:prompt_exit]
|
2648
2464
|
end
|
2649
2465
|
sel == @delegate_object[:prompt_exit] ? MenuState::EXIT : MenuState::CONTINUE
|
2650
|
-
rescue TTY::Reader::InputInterrupt
|
2651
|
-
exit 1
|
2652
2466
|
end
|
2653
2467
|
|
2654
2468
|
# user prompt to exit if the menu will be displayed again
|
@@ -2729,6 +2543,7 @@ module MarkdownExec
|
|
2729
2543
|
dependencies, selected, next_block_name: next_block_name)
|
2730
2544
|
|
2731
2545
|
else
|
2546
|
+
next_keep_code = link_state&.keep_code || link_block_data.fetch('keep', false) #/*LinkKeys::KEEP*/
|
2732
2547
|
link_history_push_and_next(
|
2733
2548
|
curr_block_name: selected.pub_name,
|
2734
2549
|
curr_document_filename: @delegate_object[:filename],
|
@@ -2737,8 +2552,10 @@ module MarkdownExec
|
|
2737
2552
|
inherited_lines: HashDelegator.code_merge(
|
2738
2553
|
link_state&.inherited_lines, code_lines
|
2739
2554
|
),
|
2555
|
+
keep_code: link_state&.keep_code,
|
2740
2556
|
next_block_name: next_block_name,
|
2741
2557
|
next_document_filename: next_document_filename,
|
2558
|
+
next_keep_code: next_keep_code,
|
2742
2559
|
next_load_file: next_document_filename == @delegate_object[:filename] ? LoadFile::REUSE : LoadFile::LOAD
|
2743
2560
|
)
|
2744
2561
|
end
|
@@ -2753,6 +2570,34 @@ module MarkdownExec
|
|
2753
2570
|
gets.chomp
|
2754
2571
|
end
|
2755
2572
|
|
2573
|
+
def read_saved_assets_for_history_table
|
2574
|
+
files = history_files(@dml_link_state).sort
|
2575
|
+
files.map do |file|
|
2576
|
+
if Regexp.new(@delegate_object[:saved_asset_match]) =~ file
|
2577
|
+
begin
|
2578
|
+
OpenStruct.new(
|
2579
|
+
file: file,
|
2580
|
+
row: format(
|
2581
|
+
@delegate_object[:saved_history_format],
|
2582
|
+
# create with default '*' so unknown parameters are given a wildcard
|
2583
|
+
$~.names.each_with_object(Hash.new('*')) do |name, hash|
|
2584
|
+
hash[name.to_sym] = $~[name]
|
2585
|
+
end
|
2586
|
+
)
|
2587
|
+
)
|
2588
|
+
rescue KeyError
|
2589
|
+
# pp $!, $@
|
2590
|
+
warn "Cannot format with: #{@delegate_object[:saved_history_format]}"
|
2591
|
+
error_handler('saved_history_format')
|
2592
|
+
return nil
|
2593
|
+
end
|
2594
|
+
else
|
2595
|
+
warn "Cannot parse name: #{file}"
|
2596
|
+
next
|
2597
|
+
end
|
2598
|
+
end&.compact
|
2599
|
+
end
|
2600
|
+
|
2756
2601
|
# Processes YAML data from the selected menu item, updating delegate objects and optionally printing formatted output.
|
2757
2602
|
# @param selected [Hash] Selected item from the menu containing a YAML body.
|
2758
2603
|
# @param tgt2 [Hash, nil] An optional target hash to update with YAML data.
|
@@ -2762,12 +2607,12 @@ module MarkdownExec
|
|
2762
2607
|
obj = {}
|
2763
2608
|
|
2764
2609
|
# concatenated body of all required blocks loaded a YAML
|
2765
|
-
data = YAML.load(
|
2610
|
+
data = (YAML.load(
|
2766
2611
|
collect_required_code_lines(
|
2767
2612
|
mdoc: mdoc, selected: selected,
|
2768
2613
|
link_state: link_state, block_source: {}
|
2769
2614
|
).join("\n")
|
2770
|
-
).transform_keys(&:to_sym)
|
2615
|
+
) || {}).transform_keys(&:to_sym)
|
2771
2616
|
|
2772
2617
|
if selected.shell == BlockType::OPTS
|
2773
2618
|
obj = data
|
@@ -2847,14 +2692,19 @@ module MarkdownExec
|
|
2847
2692
|
if @delegate_object[exception_sym] != 0
|
2848
2693
|
data = { name: name, detail: items.join(', ') }
|
2849
2694
|
warn(
|
2850
|
-
format(
|
2851
|
-
|
2852
|
-
|
2853
|
-
|
2854
|
-
|
2855
|
-
|
2856
|
-
|
2857
|
-
|
2695
|
+
AnsiString.new(format(
|
2696
|
+
@delegate_object.fetch(:exception_format_name,
|
2697
|
+
"\n%{name}"),
|
2698
|
+
data
|
2699
|
+
)).send(@delegate_object.fetch(:exception_color_name,
|
2700
|
+
:red)) +
|
2701
|
+
AnsiString.new(format(
|
2702
|
+
@delegate_object.fetch(:exception_format_detail,
|
2703
|
+
" - %{detail}\n"),
|
2704
|
+
data
|
2705
|
+
)).send(@delegate_object.fetch(
|
2706
|
+
:exception_color_detail, :yellow
|
2707
|
+
))
|
2858
2708
|
)
|
2859
2709
|
end
|
2860
2710
|
return unless (@delegate_object[exception_sym]).positive?
|
@@ -2907,6 +2757,24 @@ module MarkdownExec
|
|
2907
2757
|
@fout.fout "File saved: #{@run_state.saved_filespec}"
|
2908
2758
|
end
|
2909
2759
|
|
2760
|
+
def select_document_if_multiple(options, files, prompt:)
|
2761
|
+
# binding.irb
|
2762
|
+
return files if files.class == String ###
|
2763
|
+
return files[0] if (count = files.count) == 1
|
2764
|
+
|
2765
|
+
return unless count >= 2
|
2766
|
+
|
2767
|
+
opts = options.dup
|
2768
|
+
select_option_or_exit(
|
2769
|
+
string_send_color(
|
2770
|
+
prompt,
|
2771
|
+
:prompt_color_after_script_execution
|
2772
|
+
),
|
2773
|
+
files,
|
2774
|
+
opts.merge(per_page: opts[:select_page_height])
|
2775
|
+
)
|
2776
|
+
end
|
2777
|
+
|
2910
2778
|
# Presents a TTY prompt to select an option or exit, returns metadata including option and selected
|
2911
2779
|
def select_option_with_metadata(prompt_text, menu_items, opts = {})
|
2912
2780
|
## configure to environment
|
@@ -2948,40 +2816,6 @@ module MarkdownExec
|
|
2948
2816
|
end
|
2949
2817
|
|
2950
2818
|
selected
|
2951
|
-
rescue TTY::Reader::InputInterrupt
|
2952
|
-
exit 1
|
2953
|
-
rescue StandardError
|
2954
|
-
HashDelegator.error_handler('select_option_with_metadata')
|
2955
|
-
end
|
2956
|
-
|
2957
|
-
# Update the block name in the link state and delegate object.
|
2958
|
-
#
|
2959
|
-
# This method updates the block name based on whether it was specified
|
2960
|
-
# through the CLI or derived from the link state.
|
2961
|
-
#
|
2962
|
-
# @param link_state [LinkState] The current link state object.
|
2963
|
-
# @param block_name_from_cli [Boolean] Indicates if the block name is from CLI.
|
2964
|
-
def set_delob_filename_block_name(link_state:, block_name_from_cli:)
|
2965
|
-
@delegate_object[:filename] = link_state.document_filename
|
2966
|
-
link_state.block_name = @delegate_object[:block_name] =
|
2967
|
-
block_name_from_cli ? @cli_block_name : link_state.block_name
|
2968
|
-
end
|
2969
|
-
|
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 =
|
2973
|
-
manage_cli_selection_state(block_name_from_cli: block_name_from_cli,
|
2974
|
-
now_using_cli: now_using_cli,
|
2975
|
-
link_state: link_state)
|
2976
|
-
set_delob_filename_block_name(link_state: link_state,
|
2977
|
-
block_name_from_cli: block_name_from_cli)
|
2978
|
-
|
2979
|
-
# update @delegate_object and @menu_base_options in auto_load
|
2980
|
-
#
|
2981
|
-
blocks_in_file, menu_blocks, mdoc = mdoc_menu_and_blocks_from_nested_files(link_state)
|
2982
|
-
dump_delobj(blocks_in_file, menu_blocks, link_state)
|
2983
|
-
|
2984
|
-
[block_name_from_cli, now_using_cli, blocks_in_file, menu_blocks, mdoc]
|
2985
2819
|
end
|
2986
2820
|
|
2987
2821
|
def set_environment_variables_for_block(selected)
|
@@ -3068,7 +2902,7 @@ module MarkdownExec
|
|
3068
2902
|
stdin: if (tn = rest.match(/<(?<type>\$)?(?<name>[A-Za-z_-]\S+)/))
|
3069
2903
|
tn.named_captures.sym_keys
|
3070
2904
|
end,
|
3071
|
-
stdout: if (tn = rest.match(/>(?<type>\$)?(?<name>[
|
2905
|
+
stdout: if (tn = rest.match(/>(?<type>\$)?(?<name>[\w.\-]+)/))
|
3072
2906
|
tn.named_captures.sym_keys
|
3073
2907
|
end,
|
3074
2908
|
title: title,
|
@@ -3093,7 +2927,7 @@ module MarkdownExec
|
|
3093
2927
|
# @param line [String] The current line being processed.
|
3094
2928
|
# @param state [Hash] The current state of the parser, including flags and data related to the processing.
|
3095
2929
|
# @param opts [Hash] A hash containing various options for line and block processing.
|
3096
|
-
# @param
|
2930
|
+
# @param selected_types [Array<String>] Accumulator for lines or messages that are subject to further processing.
|
3097
2931
|
# @param block [Proc] An optional block for further processing or transformation of lines.
|
3098
2932
|
#
|
3099
2933
|
# @option state [Array<String>] :headings Current headings to be updated based on the line.
|
@@ -3103,9 +2937,9 @@ module MarkdownExec
|
|
3103
2937
|
#
|
3104
2938
|
# @option opts [Boolean] :menu_blocks_with_headings Flag indicating whether to update headings while processing.
|
3105
2939
|
#
|
3106
|
-
# @return [Void] The function modifies the `state` and `
|
2940
|
+
# @return [Void] The function modifies the `state` and `selected_types` arguments in place.
|
3107
2941
|
##
|
3108
|
-
def update_line_and_block_state(nested_line, state,
|
2942
|
+
def update_line_and_block_state(nested_line, state, selected_types,
|
3109
2943
|
&block)
|
3110
2944
|
line = nested_line.to_s
|
3111
2945
|
if line.match(@delegate_object[:fenced_start_and_end_regex])
|
@@ -3114,9 +2948,9 @@ module MarkdownExec
|
|
3114
2948
|
#
|
3115
2949
|
HashDelegator.update_menu_attrib_yield_selected(
|
3116
2950
|
fcb: state[:fcb],
|
3117
|
-
messages:
|
2951
|
+
messages: selected_types,
|
3118
2952
|
configuration: @delegate_object,
|
3119
|
-
|
2953
|
+
&block
|
3120
2954
|
)
|
3121
2955
|
state[:in_fenced_block] = false
|
3122
2956
|
else
|
@@ -3138,7 +2972,7 @@ module MarkdownExec
|
|
3138
2972
|
elsif nested_line[:depth].zero? || @delegate_object[:menu_include_imported_notes]
|
3139
2973
|
# add line if it is depth 0 or option allows it
|
3140
2974
|
#
|
3141
|
-
HashDelegator.yield_line_if_selected(line,
|
2975
|
+
HashDelegator.yield_line_if_selected(line, selected_types, &block)
|
3142
2976
|
|
3143
2977
|
else
|
3144
2978
|
# &bsp 'line is not recognized for block state'
|
@@ -3149,10 +2983,464 @@ module MarkdownExec
|
|
3149
2983
|
## apply options to current state
|
3150
2984
|
#
|
3151
2985
|
def update_menu_base(options)
|
3152
|
-
@menu_base_options
|
2986
|
+
# under simple uses, @menu_base_options may be nil
|
2987
|
+
@menu_base_options&.merge!(options)
|
3153
2988
|
@delegate_object.merge!(options)
|
3154
2989
|
end
|
3155
2990
|
|
2991
|
+
def vux_await_user_selection
|
2992
|
+
@dml_block_state = load_cli_or_user_selected_block(all_blocks: @dml_blocks_in_file,
|
2993
|
+
menu_blocks: @dml_menu_blocks,
|
2994
|
+
default: @dml_menu_default_dname)
|
2995
|
+
# &bsp '@run_state.source.block_name_from_cli:',@run_state.source.block_name_from_cli
|
2996
|
+
if !@dml_block_state
|
2997
|
+
HashDelegator.error_handler('block_state missing', { abort: true })
|
2998
|
+
elsif @dml_block_state.state == MenuState::EXIT
|
2999
|
+
# &bsp 'load_cli_or_user_selected_block -> break'
|
3000
|
+
:break
|
3001
|
+
end
|
3002
|
+
end
|
3003
|
+
|
3004
|
+
def vux_clear_menu_state
|
3005
|
+
@dml_block_state = SelectedBlockMenuState.new
|
3006
|
+
@delegate_object[:block_name] = nil
|
3007
|
+
end
|
3008
|
+
|
3009
|
+
def vux_edit_inherited
|
3010
|
+
edited = edit_text(@dml_link_state.inherited_lines_block)
|
3011
|
+
@dml_link_state.inherited_lines = edited.split("\n") if edited
|
3012
|
+
end
|
3013
|
+
|
3014
|
+
def vux_execute_and_prompt(block_name)
|
3015
|
+
@dml_block_state = block_state_for_name_from_cli(block_name)
|
3016
|
+
if @dml_block_state.block && @dml_block_state.block.shell == BlockType::OPTS
|
3017
|
+
debounce_reset
|
3018
|
+
link_state = LinkState.new
|
3019
|
+
options_state = read_show_options_and_trigger_reuse(
|
3020
|
+
link_state: link_state,
|
3021
|
+
mdoc: @dml_mdoc,
|
3022
|
+
selected: @dml_block_state.block
|
3023
|
+
)
|
3024
|
+
|
3025
|
+
update_menu_base(options_state.options)
|
3026
|
+
options_state.load_file_link_state.link_state
|
3027
|
+
return
|
3028
|
+
end
|
3029
|
+
|
3030
|
+
return :break if execute_block_in_state(block_name) == :break
|
3031
|
+
|
3032
|
+
if prompt_user_exit(block_name_from_cli: @run_state.source.block_name_from_cli,
|
3033
|
+
selected: @dml_block_state.block)
|
3034
|
+
return :break
|
3035
|
+
end
|
3036
|
+
|
3037
|
+
## order of block name processing: link block, cli, from user
|
3038
|
+
#
|
3039
|
+
@dml_link_state.block_name, @run_state.source.block_name_from_cli, cli_break =
|
3040
|
+
HashDelegator.next_link_state(
|
3041
|
+
block_name: @dml_link_state.block_name,
|
3042
|
+
block_name_from_cli: @dml_now_using_cli,
|
3043
|
+
block_state: @dml_block_state,
|
3044
|
+
was_using_cli: @dml_now_using_cli
|
3045
|
+
)
|
3046
|
+
|
3047
|
+
# &bsp '!block_name_from_ui + cli_break -> break'
|
3048
|
+
!@dml_block_state.source.block_name_from_ui && cli_break && :break
|
3049
|
+
end
|
3050
|
+
|
3051
|
+
def vux_execute_block_per_type(block_name, formatted_choice_ostructs)
|
3052
|
+
case block_name
|
3053
|
+
when formatted_choice_ostructs[:back].pub_name
|
3054
|
+
debounce_reset
|
3055
|
+
vux_navigate_back_for_ls
|
3056
|
+
|
3057
|
+
when formatted_choice_ostructs[:edit].pub_name
|
3058
|
+
debounce_reset
|
3059
|
+
vux_edit_inherited
|
3060
|
+
return :break if pause_user_exit
|
3061
|
+
|
3062
|
+
InputSequencer.next_link_state(prior_block_was_link: true)
|
3063
|
+
|
3064
|
+
when formatted_choice_ostructs[:history].pub_name
|
3065
|
+
debounce_reset
|
3066
|
+
files_table_rows = read_saved_assets_for_history_table
|
3067
|
+
return :break unless files_table_rows
|
3068
|
+
|
3069
|
+
execute_history_select(files_table_rows, stream: $stderr)
|
3070
|
+
return :break if pause_user_exit
|
3071
|
+
|
3072
|
+
InputSequencer.next_link_state(prior_block_was_link: true)
|
3073
|
+
|
3074
|
+
when formatted_choice_ostructs[:load].pub_name
|
3075
|
+
debounce_reset
|
3076
|
+
vux_load_inherited
|
3077
|
+
return :break if pause_user_exit
|
3078
|
+
|
3079
|
+
InputSequencer.next_link_state(prior_block_was_link: true)
|
3080
|
+
|
3081
|
+
when formatted_choice_ostructs[:save].pub_name
|
3082
|
+
debounce_reset
|
3083
|
+
return :break if execute_inherited_save == :break
|
3084
|
+
|
3085
|
+
InputSequencer.next_link_state(prior_block_was_link: true)
|
3086
|
+
|
3087
|
+
when formatted_choice_ostructs[:shell].pub_name
|
3088
|
+
debounce_reset
|
3089
|
+
vux_input_and_execute_shell_commands(stream: $stderr)
|
3090
|
+
return :break if pause_user_exit
|
3091
|
+
|
3092
|
+
InputSequencer.next_link_state(prior_block_was_link: true)
|
3093
|
+
|
3094
|
+
when formatted_choice_ostructs[:view].pub_name
|
3095
|
+
debounce_reset
|
3096
|
+
vux_view_inherited(stream: $stderr)
|
3097
|
+
return :break if pause_user_exit
|
3098
|
+
|
3099
|
+
InputSequencer.next_link_state(prior_block_was_link: true)
|
3100
|
+
|
3101
|
+
else
|
3102
|
+
return :break if vux_execute_and_prompt(block_name) == :break
|
3103
|
+
|
3104
|
+
InputSequencer.next_link_state(
|
3105
|
+
block_name: @dml_link_state.block_name,
|
3106
|
+
prior_block_was_link: @dml_block_state.block.shell != BlockType::BASH
|
3107
|
+
)
|
3108
|
+
end
|
3109
|
+
end
|
3110
|
+
|
3111
|
+
def vux_formatted_names_for_state_chrome_blocks(
|
3112
|
+
names: %w[back edit history load save shell view]
|
3113
|
+
)
|
3114
|
+
names.each_with_object({}) do |name, result|
|
3115
|
+
do_key = :"menu_option_#{name}_name"
|
3116
|
+
oname = HashDelegator.safeval(@delegate_object[do_key])
|
3117
|
+
dname = format(@delegate_object[:menu_link_format], oname)
|
3118
|
+
result[name.to_sym] = OpenStruct.new(
|
3119
|
+
dname: dname,
|
3120
|
+
name: dname,
|
3121
|
+
oname: dname,
|
3122
|
+
pub_name: dname.pub_name
|
3123
|
+
)
|
3124
|
+
end
|
3125
|
+
end
|
3126
|
+
|
3127
|
+
def vux_init
|
3128
|
+
@menu_base_options = @delegate_object
|
3129
|
+
@dml_link_state = LinkState.new(
|
3130
|
+
block_name: @delegate_object[:block_name],
|
3131
|
+
document_filename: @delegate_object[:filename]
|
3132
|
+
)
|
3133
|
+
@run_state.source.block_name_from_cli = @dml_link_state.block_name.present?
|
3134
|
+
@cli_block_name = @dml_link_state.block_name
|
3135
|
+
@dml_now_using_cli = @run_state.source.block_name_from_cli
|
3136
|
+
@dml_menu_default_dname = nil
|
3137
|
+
@dml_block_state = SelectedBlockMenuState.new
|
3138
|
+
@doc_saved_lines_files = []
|
3139
|
+
|
3140
|
+
@run_state.batch_random = Random.new.rand
|
3141
|
+
@run_state.batch_index = 0
|
3142
|
+
|
3143
|
+
@run_state.files = StreamsOut.new
|
3144
|
+
end
|
3145
|
+
|
3146
|
+
def vux_input_and_execute_shell_commands(stream:)
|
3147
|
+
loop do
|
3148
|
+
command = prompt_for_command(AnsiString.new(":MDE #{Time.now.strftime('%FT%TZ')}> ").send(:bgreen))
|
3149
|
+
break if !command.present? || command == 'exit'
|
3150
|
+
|
3151
|
+
exit_status = execute_command_with_streams(
|
3152
|
+
[@delegate_object[:shell], '-c', command]
|
3153
|
+
)
|
3154
|
+
case exit_status
|
3155
|
+
when 0
|
3156
|
+
stream.puts "#{'OK'.green} #{exit_status}"
|
3157
|
+
else
|
3158
|
+
stream.puts "#{'ERR'.bred} #{exit_status}"
|
3159
|
+
end
|
3160
|
+
end
|
3161
|
+
end
|
3162
|
+
|
3163
|
+
## load file with code lines per options
|
3164
|
+
#
|
3165
|
+
def vux_load_code_files_into_state
|
3166
|
+
return unless @menu_base_options[:load_code].present?
|
3167
|
+
|
3168
|
+
@dml_link_state.inherited_lines =
|
3169
|
+
@menu_base_options[:load_code].split(':').map do |path|
|
3170
|
+
File.readlines(path, chomp: true)
|
3171
|
+
end.flatten(1)
|
3172
|
+
|
3173
|
+
inherited_block_names = []
|
3174
|
+
inherited_dependencies = {}
|
3175
|
+
selected = FCB.new(oname: 'load_code')
|
3176
|
+
pop_add_current_code_to_head_and_trigger_load(
|
3177
|
+
@dml_link_state, inherited_block_names,
|
3178
|
+
code_lines, inherited_dependencies, selected
|
3179
|
+
)
|
3180
|
+
end
|
3181
|
+
|
3182
|
+
def vux_load_inherited
|
3183
|
+
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename,
|
3184
|
+
@delegate_object[:document_saved_lines_glob])
|
3185
|
+
load_filespec = load_filespec_from_expression(sf)
|
3186
|
+
return unless load_filespec
|
3187
|
+
|
3188
|
+
@dml_link_state.inherited_lines_append(
|
3189
|
+
File.readlines(load_filespec, chomp: true)
|
3190
|
+
)
|
3191
|
+
end
|
3192
|
+
|
3193
|
+
# Select and execute a code block from a Markdown document.
|
3194
|
+
#
|
3195
|
+
# This method allows the user to interactively select a code block from a
|
3196
|
+
# Markdown document, obtain approval, and execute the chosen block of code.
|
3197
|
+
#
|
3198
|
+
# @return [Nil] Returns nil if no code block is selected or an error occurs.
|
3199
|
+
def vux_main_loop
|
3200
|
+
vux_init
|
3201
|
+
vux_load_code_files_into_state
|
3202
|
+
formatted_choice_ostructs = vux_formatted_names_for_state_chrome_blocks
|
3203
|
+
|
3204
|
+
block_list = [@delegate_object[:block_name]].select(&:present?).compact + @delegate_object[:input_cli_rest]
|
3205
|
+
@delegate_object[:block_name] = nil
|
3206
|
+
|
3207
|
+
process_commands(
|
3208
|
+
arguments: @p_all_arguments,
|
3209
|
+
named_procs: yield(:command_names, @delegate_object),
|
3210
|
+
options_parsed: @p_options_parsed,
|
3211
|
+
rest: @p_rest,
|
3212
|
+
enable_search: @delegate_object[:default_find_select_open]
|
3213
|
+
) do |type, data|
|
3214
|
+
case type
|
3215
|
+
when ArgPro::ActSetBlockName
|
3216
|
+
@delegate_object[:block_name] = data
|
3217
|
+
@delegate_object[:input_cli_rest] = ''
|
3218
|
+
when ArgPro::ConvertValue
|
3219
|
+
# call for side effects, output, or exit
|
3220
|
+
data[0].call(data[1])
|
3221
|
+
when ArgPro::ActFileIsMissing
|
3222
|
+
raise FileMissingError, data, caller
|
3223
|
+
when ArgPro::ActFind
|
3224
|
+
find_value(data, execute_chosen_found: true)
|
3225
|
+
when ArgPro::ActSetFileName
|
3226
|
+
@delegate_object[:filename] = data
|
3227
|
+
when ArgPro::ActSetPath
|
3228
|
+
@delegate_object[:path] = data
|
3229
|
+
when ArgPro::CallProcess
|
3230
|
+
yield :call_proc, [@delegate_object, data]
|
3231
|
+
when ArgPro::ActSetOption
|
3232
|
+
@delegate_object[data[0]] = data[1]
|
3233
|
+
else
|
3234
|
+
raise
|
3235
|
+
end
|
3236
|
+
end
|
3237
|
+
|
3238
|
+
InputSequencer.new(
|
3239
|
+
@delegate_object[:filename],
|
3240
|
+
block_list
|
3241
|
+
).run do |msg, data|
|
3242
|
+
# &bt msg
|
3243
|
+
case msg
|
3244
|
+
when :parse_document # once for each menu
|
3245
|
+
vux_parse_document
|
3246
|
+
vux_menu_append_history_files(formatted_choice_ostructs)
|
3247
|
+
vux_publish_document_file_name_for_external_automation
|
3248
|
+
|
3249
|
+
when :display_menu
|
3250
|
+
vux_clear_menu_state
|
3251
|
+
|
3252
|
+
when :user_choice
|
3253
|
+
vux_user_selected_block_name
|
3254
|
+
|
3255
|
+
when :execute_block
|
3256
|
+
ret = vux_execute_block_per_type(data, formatted_choice_ostructs)
|
3257
|
+
vux_publish_block_name_for_external_automation(data)
|
3258
|
+
ret
|
3259
|
+
|
3260
|
+
when :close_ux
|
3261
|
+
if @vux_pipe_open.present? && File.exist?(@vux_pipe_open)
|
3262
|
+
@vux_pipe_open.close
|
3263
|
+
@vux_pipe_open = nil
|
3264
|
+
end
|
3265
|
+
if @vux_pipe_created.present? && File.exist?(@vux_pipe_created)
|
3266
|
+
File.delete(@vux_pipe_created)
|
3267
|
+
@vux_pipe_created = nil
|
3268
|
+
end
|
3269
|
+
|
3270
|
+
when :exit?
|
3271
|
+
data == $texit
|
3272
|
+
|
3273
|
+
when :stay?
|
3274
|
+
data == $stay
|
3275
|
+
|
3276
|
+
else
|
3277
|
+
raise "Invalid message: #{msg}"
|
3278
|
+
|
3279
|
+
end
|
3280
|
+
end
|
3281
|
+
end
|
3282
|
+
|
3283
|
+
def vux_menu_append_history_files(formatted_choice_ostructs)
|
3284
|
+
if @delegate_object[:menu_for_history]
|
3285
|
+
history_files(@dml_link_state).tap do |files|
|
3286
|
+
if files.count.positive?
|
3287
|
+
dml_menu_append_chrome_item(
|
3288
|
+
formatted_choice_ostructs[:history].oname, files.count,
|
3289
|
+
'files', menu_state: MenuState::HISTORY
|
3290
|
+
)
|
3291
|
+
end
|
3292
|
+
end
|
3293
|
+
end
|
3294
|
+
|
3295
|
+
return unless @delegate_object[:menu_for_saved_lines] && @delegate_object[:document_saved_lines_glob].present?
|
3296
|
+
|
3297
|
+
sf = document_name_in_glob_as_file_name(
|
3298
|
+
@dml_link_state.document_filename,
|
3299
|
+
@delegate_object[:document_saved_lines_glob]
|
3300
|
+
)
|
3301
|
+
files = sf ? Dir.glob(sf) : []
|
3302
|
+
@doc_saved_lines_files = files.count.positive? ? files : []
|
3303
|
+
|
3304
|
+
lines_count = @dml_link_state.inherited_lines_count
|
3305
|
+
|
3306
|
+
# add menu items (glob, load, save) and enable selectively
|
3307
|
+
if files.count.positive? || lines_count.positive?
|
3308
|
+
menu_add_disabled_option(sf)
|
3309
|
+
end
|
3310
|
+
if files.count.positive?
|
3311
|
+
dml_menu_append_chrome_item(formatted_choice_ostructs[:load].dname, files.count, 'files',
|
3312
|
+
menu_state: MenuState::LOAD)
|
3313
|
+
end
|
3314
|
+
if @delegate_object[:menu_inherited_lines_edit_always] || lines_count.positive?
|
3315
|
+
dml_menu_append_chrome_item(formatted_choice_ostructs[:edit].dname, lines_count, 'lines',
|
3316
|
+
menu_state: MenuState::EDIT)
|
3317
|
+
end
|
3318
|
+
if lines_count.positive?
|
3319
|
+
dml_menu_append_chrome_item(formatted_choice_ostructs[:save].dname, 1, '',
|
3320
|
+
menu_state: MenuState::SAVE)
|
3321
|
+
end
|
3322
|
+
if lines_count.positive?
|
3323
|
+
dml_menu_append_chrome_item(formatted_choice_ostructs[:view].dname, 1, '',
|
3324
|
+
menu_state: MenuState::VIEW)
|
3325
|
+
end
|
3326
|
+
# rubocop:disable Style/GuardClause
|
3327
|
+
if @delegate_object[:menu_with_shell]
|
3328
|
+
dml_menu_append_chrome_item(formatted_choice_ostructs[:shell].dname, 1, '',
|
3329
|
+
menu_state: MenuState::SHELL)
|
3330
|
+
end
|
3331
|
+
# rubocop:enable Style/GuardClause
|
3332
|
+
|
3333
|
+
# # reflect new menu items
|
3334
|
+
# @dml_mdoc = MDoc.new(@dml_menu_blocks)
|
3335
|
+
end
|
3336
|
+
|
3337
|
+
def vux_navigate_back_for_ls
|
3338
|
+
InputSequencer.merge_link_state(
|
3339
|
+
@dml_link_state,
|
3340
|
+
InputSequencer.next_link_state(
|
3341
|
+
**execute_navigate_back.merge(prior_block_was_link: true)
|
3342
|
+
)
|
3343
|
+
)
|
3344
|
+
end
|
3345
|
+
|
3346
|
+
def vux_parse_document
|
3347
|
+
@run_state.batch_index += 1
|
3348
|
+
@run_state.in_own_window = false
|
3349
|
+
|
3350
|
+
@run_state.source.block_name_from_cli, @dml_now_using_cli =
|
3351
|
+
manage_cli_selection_state(
|
3352
|
+
block_name_from_cli: @run_state.source.block_name_from_cli,
|
3353
|
+
now_using_cli: @dml_now_using_cli,
|
3354
|
+
link_state: @dml_link_state
|
3355
|
+
)
|
3356
|
+
|
3357
|
+
@delegate_object[:filename] = @dml_link_state.document_filename
|
3358
|
+
@dml_link_state.block_name = @delegate_object[:block_name] =
|
3359
|
+
@run_state.source.block_name_from_cli ?
|
3360
|
+
@cli_block_name :
|
3361
|
+
@dml_link_state.block_name
|
3362
|
+
|
3363
|
+
# update @delegate_object and @menu_base_options in auto_load
|
3364
|
+
#
|
3365
|
+
@dml_blocks_in_file, @dml_menu_blocks, @dml_mdoc =
|
3366
|
+
mdoc_menu_and_blocks_from_nested_files(@dml_link_state)
|
3367
|
+
dump_delobj(@dml_blocks_in_file, @dml_menu_blocks, @dml_link_state)
|
3368
|
+
# &bsp 'loop', @run_state.source.block_name_from_cli, @cli_block_name
|
3369
|
+
end
|
3370
|
+
|
3371
|
+
def publish_for_external_automation(message:)
|
3372
|
+
return if @delegate_object[:publish_document_file_name].empty?
|
3373
|
+
|
3374
|
+
pipe_path = absolute_path(@delegate_object[:publish_document_file_name])
|
3375
|
+
|
3376
|
+
case @delegate_object[:publish_document_file_mode]
|
3377
|
+
when 'append'
|
3378
|
+
File.write(pipe_path, message + "\n", mode: 'a')
|
3379
|
+
when 'fifo'
|
3380
|
+
unless @vux_pipe_open
|
3381
|
+
unless File.exist?(pipe_path)
|
3382
|
+
FileUtils.mkfifo(pipe_path)
|
3383
|
+
@vux_pipe_created = pipe_path
|
3384
|
+
end
|
3385
|
+
@vux_pipe_open = File.open(pipe_path, 'w')
|
3386
|
+
end
|
3387
|
+
@vux_pipe_open.puts(message + "\n")
|
3388
|
+
@vux_pipe_open.flush
|
3389
|
+
when 'write'
|
3390
|
+
File.write(pipe_path, message)
|
3391
|
+
else
|
3392
|
+
raise 'Invalid publish_document_file_mode:' \
|
3393
|
+
" #{@delegate_object[:publish_document_file_mode]}"
|
3394
|
+
end
|
3395
|
+
end
|
3396
|
+
|
3397
|
+
def vux_publish_block_name_for_external_automation(block_name)
|
3398
|
+
publish_for_external_automation(
|
3399
|
+
message: format(
|
3400
|
+
@delegate_object[:publish_block_name_format],
|
3401
|
+
{ block: block_name,
|
3402
|
+
document: @delegate_object[:filename],
|
3403
|
+
time: Time.now.utc.strftime(
|
3404
|
+
@delegate_object[:publish_time_format]
|
3405
|
+
) }
|
3406
|
+
)
|
3407
|
+
)
|
3408
|
+
end
|
3409
|
+
|
3410
|
+
def vux_publish_document_file_name_for_external_automation
|
3411
|
+
return unless @delegate_object[:publish_document_file_name].present?
|
3412
|
+
|
3413
|
+
publish_for_external_automation(
|
3414
|
+
message: format(
|
3415
|
+
@delegate_object[:publish_document_name_format],
|
3416
|
+
{ document: @delegate_object[:filename],
|
3417
|
+
time: Time.now.utc.strftime(
|
3418
|
+
@delegate_object[:publish_time_format]
|
3419
|
+
) }
|
3420
|
+
)
|
3421
|
+
)
|
3422
|
+
end
|
3423
|
+
|
3424
|
+
# return :break to break from loop
|
3425
|
+
def vux_user_selected_block_name
|
3426
|
+
if @dml_link_state.block_name.present?
|
3427
|
+
# @prior_block_was_link = true
|
3428
|
+
@dml_block_state.block = blocks_find_by_block_name(@dml_blocks_in_file,
|
3429
|
+
@dml_link_state.block_name)
|
3430
|
+
@dml_link_state.block_name = nil
|
3431
|
+
else
|
3432
|
+
# puts "? - Select a block to execute (or type #{$texit} to exit):"
|
3433
|
+
return :break if vux_await_user_selection == :break # into @dml_block_state
|
3434
|
+
return :break if @dml_block_state.block.nil? # no block matched
|
3435
|
+
end
|
3436
|
+
# puts "! - Executing block: #{data}"
|
3437
|
+
@dml_block_state.block&.pub_name
|
3438
|
+
end
|
3439
|
+
|
3440
|
+
def vux_view_inherited(stream:)
|
3441
|
+
stream.puts @dml_link_state.inherited_lines_block
|
3442
|
+
end
|
3443
|
+
|
3156
3444
|
def wait_for_stream_processing
|
3157
3445
|
@process_mutex.synchronize do
|
3158
3446
|
@process_cv.wait(@process_mutex)
|
@@ -3165,11 +3453,13 @@ module MarkdownExec
|
|
3165
3453
|
block_state = wait_for_user_selection(all_blocks, menu_blocks, default)
|
3166
3454
|
handle_back_or_continue(block_state)
|
3167
3455
|
block_state
|
3168
|
-
rescue StandardError
|
3169
|
-
HashDelegator.error_handler('wait_for_user_selected_block')
|
3170
3456
|
end
|
3171
3457
|
|
3172
3458
|
def wait_for_user_selection(_all_blocks, menu_blocks, default)
|
3459
|
+
if @delegate_object[:clear_screen_for_select_block]
|
3460
|
+
printf("\e[1;1H\e[2J")
|
3461
|
+
end
|
3462
|
+
|
3173
3463
|
prompt_title = string_send_color(
|
3174
3464
|
@delegate_object[:prompt_select_block].to_s, :prompt_color_after_script_execution
|
3175
3465
|
)
|
@@ -3823,31 +4113,31 @@ module MarkdownExec
|
|
3823
4113
|
@hd.instance_variable_set(:@run_state, mock('run_state'))
|
3824
4114
|
end
|
3825
4115
|
|
3826
|
-
def test_format_execution_stream_with_valid_key
|
3827
|
-
|
3828
|
-
|
3829
|
-
|
3830
|
-
|
4116
|
+
# def test_format_execution_stream_with_valid_key
|
4117
|
+
# result = HashDelegator.format_execution_stream(
|
4118
|
+
# { stdout: %w[output1 output2] },
|
4119
|
+
# ExecutionStreams::STD_OUT
|
4120
|
+
# )
|
3831
4121
|
|
3832
|
-
|
3833
|
-
end
|
4122
|
+
# assert_equal "output1\noutput2", result
|
4123
|
+
# end
|
3834
4124
|
|
3835
|
-
def test_format_execution_stream_with_empty_key
|
3836
|
-
|
4125
|
+
# def test_format_execution_stream_with_empty_key
|
4126
|
+
# @hd.instance_variable_get(:@run_state).stubs(:files).returns({})
|
3837
4127
|
|
3838
|
-
|
3839
|
-
|
4128
|
+
# result = HashDelegator.format_execution_stream(nil,
|
4129
|
+
# ExecutionStreams::STD_ERR)
|
3840
4130
|
|
3841
|
-
|
3842
|
-
end
|
4131
|
+
# assert_equal '', result
|
4132
|
+
# end
|
3843
4133
|
|
3844
|
-
def test_format_execution_stream_with_nil_files
|
3845
|
-
|
4134
|
+
# def test_format_execution_stream_with_nil_files
|
4135
|
+
# @hd.instance_variable_get(:@run_state).stubs(:files).returns(nil)
|
3846
4136
|
|
3847
|
-
|
4137
|
+
# result = HashDelegator.format_execution_stream(nil, :stdin)
|
3848
4138
|
|
3849
|
-
|
3850
|
-
end
|
4139
|
+
# assert_equal '', result
|
4140
|
+
# end
|
3851
4141
|
end
|
3852
4142
|
|
3853
4143
|
class TestHashDelegatorHandleBackLink < Minitest::Test
|
@@ -3856,16 +4146,14 @@ module MarkdownExec
|
|
3856
4146
|
@hd.stubs(:history_state_pop)
|
3857
4147
|
end
|
3858
4148
|
|
3859
|
-
def
|
4149
|
+
def test_pop_link_history_new_state
|
3860
4150
|
# Verifying that history_state_pop is called
|
3861
4151
|
# @hd.expects(:history_state_pop).once
|
3862
4152
|
|
3863
|
-
result = @hd.
|
4153
|
+
result = @hd.pop_link_history_new_state
|
3864
4154
|
|
3865
|
-
# Asserting the result is an instance of
|
3866
|
-
|
3867
|
-
assert_equal LoadFile::LOAD, result.load_file
|
3868
|
-
assert_nil result.link_state.block_name
|
4155
|
+
# Asserting the result is an instance of LinkState
|
4156
|
+
assert_nil result.block_name
|
3869
4157
|
end
|
3870
4158
|
end
|
3871
4159
|
|
@@ -3952,7 +4240,7 @@ module MarkdownExec
|
|
3952
4240
|
def setup
|
3953
4241
|
@hd = HashDelegator.new
|
3954
4242
|
@hd.instance_variable_set(:@run_state,
|
3955
|
-
OpenStruct.new(files:
|
4243
|
+
OpenStruct.new(files: StreamsOut.new))
|
3956
4244
|
@hd.instance_variable_set(:@delegate_object,
|
3957
4245
|
{ output_stdout: true })
|
3958
4246
|
end
|
@@ -3964,9 +4252,8 @@ module MarkdownExec
|
|
3964
4252
|
Thread.new { @hd.handle_stream(stream: stream, file_type: file_type) }
|
3965
4253
|
|
3966
4254
|
@hd.wait_for_stream_processing
|
3967
|
-
|
3968
4255
|
assert_equal ['line 1', 'line 2'],
|
3969
|
-
@hd.instance_variable_get(:@run_state).files
|
4256
|
+
@hd.instance_variable_get(:@run_state).files.stream_lines(ExecutionStreams::STD_OUT)
|
3970
4257
|
end
|
3971
4258
|
|
3972
4259
|
def test_handle_stream_with_io_error
|
@@ -3979,7 +4266,7 @@ module MarkdownExec
|
|
3979
4266
|
@hd.wait_for_stream_processing
|
3980
4267
|
|
3981
4268
|
assert_equal [],
|
3982
|
-
@hd.instance_variable_get(:@run_state).files
|
4269
|
+
@hd.instance_variable_get(:@run_state).files.stream_lines(ExecutionStreams::STD_OUT)
|
3983
4270
|
end
|
3984
4271
|
end
|
3985
4272
|
|
@@ -3997,9 +4284,9 @@ module MarkdownExec
|
|
3997
4284
|
def test_iter_blocks_from_nested_files
|
3998
4285
|
@hd.cfile.expect(:readlines, ['line 1', 'line 2'], ['test.md'],
|
3999
4286
|
import_paths: nil)
|
4000
|
-
|
4287
|
+
selected_types = ['filtered message']
|
4001
4288
|
|
4002
|
-
result = @hd.iter_blocks_from_nested_files {
|
4289
|
+
result = @hd.iter_blocks_from_nested_files { selected_types }
|
4003
4290
|
assert_equal ['line 1', 'line 2'], result
|
4004
4291
|
|
4005
4292
|
@hd.cfile.verify
|
@@ -4024,11 +4311,11 @@ module MarkdownExec
|
|
4024
4311
|
})
|
4025
4312
|
@hd.stubs(:menu_chrome_formatted_option).with(:menu_option_back_name).returns('-- Back --')
|
4026
4313
|
@hd.stubs(:string_send_color).with('-- Back --',
|
4027
|
-
:menu_chrome_color).returns('-- Back --'.red)
|
4314
|
+
:menu_chrome_color).returns(AnsiString.new('-- Back --').red)
|
4028
4315
|
end
|
4029
4316
|
|
4030
4317
|
def test_menu_chrome_colored_option_with_color
|
4031
|
-
assert_equal '-- Back --'.red,
|
4318
|
+
assert_equal AnsiString.new('-- Back --').red,
|
4032
4319
|
@hd.menu_chrome_colored_option(:menu_option_back_name)
|
4033
4320
|
end
|
4034
4321
|
|
@@ -4092,10 +4379,11 @@ module MarkdownExec
|
|
4092
4379
|
end
|
4093
4380
|
|
4094
4381
|
def test_string_send_color
|
4095
|
-
assert_equal 'Hello'.red,
|
4096
|
-
|
4382
|
+
assert_equal AnsiString.new('Hello').red,
|
4383
|
+
@hd.string_send_color('Hello', :red)
|
4384
|
+
assert_equal AnsiString.new('World').green,
|
4097
4385
|
@hd.string_send_color('World', :green)
|
4098
|
-
assert_equal 'Default'.plain,
|
4386
|
+
assert_equal AnsiString.new('Default').plain,
|
4099
4387
|
@hd.string_send_color('Default', :blue)
|
4100
4388
|
end
|
4101
4389
|
end
|
@@ -4285,10 +4573,7 @@ module MarkdownExec
|
|
4285
4573
|
|
4286
4574
|
def test_prompt_for_filespec_with_interruption
|
4287
4575
|
$stdin = StringIO.new
|
4288
|
-
# rubocop disable:Lint/NestedMethodDefinition
|
4289
4576
|
def $stdin.gets; raise Interrupt; end
|
4290
|
-
# rubocop enable:Lint/NestedMethodDefinition
|
4291
|
-
|
4292
4577
|
result = prompt_for_filespec_with_wildcard('*.txt')
|
4293
4578
|
assert_nil result
|
4294
4579
|
end
|