markdown_exec 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -2
- data/CHANGELOG.md +14 -1
- data/Gemfile +3 -3
- data/Gemfile.lock +134 -92
- data/README.md +13 -13
- data/bin/tab_completion.sh +14 -3
- data/bin/tab_completion.sh.erb +0 -1
- data/examples/bash-blocks.md +58 -0
- data/examples/block-names.md +27 -0
- data/examples/indent.md +43 -2
- data/examples/link-blocks-block.md +5 -0
- data/examples/link-blocks-load-save.md +59 -0
- data/examples/link-blocks-vars.md +56 -0
- data/examples/linked.md +6 -101
- data/examples/opts-blocks-require.md +28 -0
- data/examples/{port.md → port-blocks.md} +18 -9
- data/examples/save.md +76 -4
- data/examples/vars-blocks.md +38 -0
- data/lib/constants.rb +1 -1
- data/lib/fcb.rb +202 -16
- data/lib/filter.rb +12 -12
- data/lib/hash_delegator.rb +647 -321
- data/lib/link_history.rb +34 -1
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +56 -75
- data/lib/mdoc.rb +112 -57
- data/lib/menu.src.yml +34 -21
- data/lib/menu.yml +30 -19
- data/lib/namer.rb +50 -0
- data/lib/poly.rb +152 -0
- data/lib/saved_assets.rb +4 -11
- data/lib/string_util.rb +0 -1
- metadata +14 -6
- data/examples/vars.md +0 -20
- /data/examples/{opts.md → opts-blocks.md} +0 -0
- /data/examples/{pass-through.md → pass-through-arguments.md} +0 -0
data/lib/link_history.rb
CHANGED
@@ -2,10 +2,13 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# encoding=utf-8
|
5
|
+
|
6
|
+
$pd = false unless defined?($pd)
|
7
|
+
|
5
8
|
module MarkdownExec
|
6
9
|
class LinkState
|
7
10
|
attr_accessor :block_name, :display_menu, :document_filename,
|
8
|
-
:inherited_block_names, :inherited_dependencies,
|
11
|
+
:inherited_block_names, :inherited_dependencies,
|
9
12
|
:prior_block_was_link
|
10
13
|
|
11
14
|
# Initialize the LinkState with keyword arguments for each attribute.
|
@@ -45,6 +48,36 @@ module MarkdownExec
|
|
45
48
|
other.inherited_lines == inherited_lines &&
|
46
49
|
other.prior_block_was_link == prior_block_was_link
|
47
50
|
end
|
51
|
+
|
52
|
+
def inherited_lines
|
53
|
+
@inherited_lines.tap { |ret| pp ['LinkState.inherited_lines() ->', ret] if $pd }
|
54
|
+
end
|
55
|
+
|
56
|
+
def inherited_lines=(value)
|
57
|
+
@inherited_lines = value.tap { |ret| pp ['LinkState.inherited_lines=() ->', ret] if $pd }
|
58
|
+
end
|
59
|
+
|
60
|
+
def inherited_lines_append(value)
|
61
|
+
@inherited_lines = ((@inherited_lines || []) + value).tap { |ret| pp ['LinkState.inherited_lines_append() ->', ret] if $pd }
|
62
|
+
end
|
63
|
+
|
64
|
+
def inherited_lines_block
|
65
|
+
@inherited_lines.join("\n").tap { |ret| pp ['LinkState.inherited_lines_block() ->', ret] if $pd }
|
66
|
+
end
|
67
|
+
|
68
|
+
def inherited_lines_count
|
69
|
+
(@inherited_lines&.count || 0).tap { |ret| pp ['LinkState.inherited_lines_count() ->', ret] if $pd }
|
70
|
+
end
|
71
|
+
|
72
|
+
def inherited_lines_map
|
73
|
+
@inherited_lines.map do |line|
|
74
|
+
yield line
|
75
|
+
end.tap { |ret| pp ['LinkState.inherited_lines_map() ->', ret] if $pd }
|
76
|
+
end
|
77
|
+
|
78
|
+
def inherited_lines_present?
|
79
|
+
@inherited_lines.present?.tap { |ret| pp ['LinkState.inherited_lines_present?() ->', ret] if $pd }
|
80
|
+
end
|
48
81
|
end
|
49
82
|
|
50
83
|
class LinkHistory
|
data/lib/markdown_exec.rb
CHANGED
@@ -45,6 +45,8 @@ tap_config envvar: MarkdownExec::TAP_DEBUG
|
|
45
45
|
$stderr.sync = true
|
46
46
|
$stdout.sync = true
|
47
47
|
|
48
|
+
$pd = false unless defined?($pd)
|
49
|
+
|
48
50
|
ARGV_SEP = '--'
|
49
51
|
|
50
52
|
# custom error: file specified is missing
|
@@ -86,20 +88,6 @@ def extract_named_captures_from_option(str, option)
|
|
86
88
|
str.match(Regexp.new(option))&.named_captures&.sym_keys
|
87
89
|
end
|
88
90
|
|
89
|
-
# :reek:UtilityFunction
|
90
|
-
def list_recent_output(saved_stdout_folder, saved_stdout_glob,
|
91
|
-
list_count)
|
92
|
-
SavedFilesMatcher.most_recent_list(saved_stdout_folder,
|
93
|
-
saved_stdout_glob, list_count)
|
94
|
-
end
|
95
|
-
|
96
|
-
# :reek:UtilityFunction
|
97
|
-
def list_recent_scripts(saved_script_folder, saved_script_glob,
|
98
|
-
list_count)
|
99
|
-
SavedFilesMatcher.most_recent_list(saved_script_folder,
|
100
|
-
saved_script_glob, list_count)
|
101
|
-
end
|
102
|
-
|
103
91
|
# execute markdown documents
|
104
92
|
#
|
105
93
|
module MarkdownExec
|
@@ -167,12 +155,14 @@ module MarkdownExec
|
|
167
155
|
|
168
156
|
# Conditionally add directory names if data is present
|
169
157
|
unless directory_names[:data].count.zero?
|
170
|
-
choices << { disabled: '',
|
158
|
+
choices << { disabled: '',
|
159
|
+
name: "in #{directory_names[:section_title]}".send(@chrome_color) }
|
171
160
|
choices += files_in_directories
|
172
161
|
end
|
173
162
|
|
174
163
|
# Adding found in block names
|
175
|
-
choices << { disabled: '',
|
164
|
+
choices << { disabled: '',
|
165
|
+
name: "in #{found_in_block_names[:section_title]}".send(@chrome_color) }
|
176
166
|
|
177
167
|
choices += vbn
|
178
168
|
|
@@ -186,16 +176,22 @@ module MarkdownExec
|
|
186
176
|
{
|
187
177
|
section_title: 'directory names',
|
188
178
|
data: matched_directories,
|
189
|
-
formatted_text: [{ content: AnsiFormatter.new(search_options).format_and_highlight_array(
|
179
|
+
formatted_text: [{ content: AnsiFormatter.new(search_options).format_and_highlight_array(
|
180
|
+
matched_directories, highlight: [highlight_value]
|
181
|
+
) }]
|
190
182
|
}
|
191
183
|
end
|
192
184
|
|
193
|
-
def found_in_block_names(search_options, highlight_value,
|
185
|
+
def found_in_block_names(search_options, highlight_value,
|
186
|
+
formspec: '=%<index>4.d: %<line>s')
|
194
187
|
matched_contents = (find_file_contents do |line|
|
195
|
-
read_block_name(line, search_options[:fenced_start_and_end_regex],
|
188
|
+
read_block_name(line, search_options[:fenced_start_and_end_regex],
|
189
|
+
search_options[:block_name_match], search_options[:block_name_nick_match])
|
196
190
|
end).map.with_index do |(file, contents), index|
|
197
191
|
# [file, contents.map { |detail| format(formspec, detail.index, detail.line) }, index]
|
198
|
-
[file, contents.map
|
192
|
+
[file, contents.map do |detail|
|
193
|
+
format(formspec, { index: detail.index, line: detail.line })
|
194
|
+
end, index]
|
199
195
|
end
|
200
196
|
{
|
201
197
|
section_title: 'block names',
|
@@ -222,7 +218,8 @@ module MarkdownExec
|
|
222
218
|
}
|
223
219
|
end
|
224
220
|
|
225
|
-
def read_block_name(line, fenced_start_and_end_regex, block_name_match,
|
221
|
+
def read_block_name(line, fenced_start_and_end_regex, block_name_match,
|
222
|
+
block_name_nick_match)
|
226
223
|
return unless line.match(fenced_start_and_end_regex)
|
227
224
|
|
228
225
|
bm = extract_named_captures_from_option(line, block_name_match)
|
@@ -241,7 +238,6 @@ module MarkdownExec
|
|
241
238
|
##
|
242
239
|
#
|
243
240
|
# :reek:DuplicateMethodCall { allow_calls: ['block', 'item', 'lm', 'opts', 'option', '@options', 'required_blocks'] }
|
244
|
-
# rubocop:enable Layout/LineLength
|
245
241
|
# :reek:MissingSafeMethod { exclude: [ read_configuration_file! ] }
|
246
242
|
# :reek:TooManyInstanceVariables ### temp
|
247
243
|
# :reek:TooManyMethods ### temp
|
@@ -267,6 +263,20 @@ module MarkdownExec
|
|
267
263
|
)
|
268
264
|
end
|
269
265
|
|
266
|
+
# :reek:UtilityFunction
|
267
|
+
def list_recent_output(saved_stdout_folder, saved_stdout_glob,
|
268
|
+
list_count)
|
269
|
+
SavedFilesMatcher.most_recent_list(saved_stdout_folder,
|
270
|
+
saved_stdout_glob, list_count)
|
271
|
+
end
|
272
|
+
|
273
|
+
# :reek:UtilityFunction
|
274
|
+
def list_recent_scripts(saved_script_folder, saved_script_glob,
|
275
|
+
list_count)
|
276
|
+
SavedFilesMatcher.most_recent_list(saved_script_folder,
|
277
|
+
saved_script_glob, list_count)
|
278
|
+
end
|
279
|
+
|
270
280
|
def warn_format(name, message, opts = {})
|
271
281
|
Exceptions.warn_format(
|
272
282
|
"CachedNestedFileReader.#{name} -- #{message}",
|
@@ -390,8 +400,6 @@ module MarkdownExec
|
|
390
400
|
},
|
391
401
|
pwd: -> { @fout.fout File.expand_path('..', __dir__) },
|
392
402
|
run_last_script: -> { run_last_script },
|
393
|
-
select_recent_output: -> { select_recent_output },
|
394
|
-
select_recent_script: -> { select_recent_script },
|
395
403
|
tab_completions: -> { @fout.fout tab_completions },
|
396
404
|
menu_export: -> { @fout.fout menu_export }
|
397
405
|
}
|
@@ -480,7 +488,9 @@ module MarkdownExec
|
|
480
488
|
find_files('*', [dn], exclude_dirs: true)
|
481
489
|
end.flatten(1).map { |str| FileInMenu.for_menu(str) }
|
482
490
|
|
483
|
-
|
491
|
+
unless file_names[:data]&.count.positive? || files_in_directories&.count.positive? || found_in_block_names[:data]&.count.positive?
|
492
|
+
return { exit: true }
|
493
|
+
end
|
484
494
|
|
485
495
|
vbn = found_in_block_names[:matched_contents].map do |matched_contents|
|
486
496
|
filename, details, = matched_contents
|
@@ -488,10 +498,13 @@ module MarkdownExec
|
|
488
498
|
details,
|
489
499
|
highlight: [value]
|
490
500
|
)
|
491
|
-
[FileInMenu.for_menu(filename)] + nexo.map
|
501
|
+
[FileInMenu.for_menu(filename)] + nexo.map do |str|
|
502
|
+
{ disabled: '', name: (' ' * 20) + str }
|
503
|
+
end
|
492
504
|
end.flatten
|
493
505
|
|
494
|
-
choices = MenuBuilder.new.build_menu(file_names, directory_names, found_in_block_names,
|
506
|
+
choices = MenuBuilder.new.build_menu(file_names, directory_names, found_in_block_names,
|
507
|
+
files_in_directories, vbn)
|
495
508
|
|
496
509
|
@options[:filename] = FileInMenu.from_menu(
|
497
510
|
select_document_if_multiple(
|
@@ -545,7 +558,8 @@ module MarkdownExec
|
|
545
558
|
->(_) { exit }
|
546
559
|
when 'find', 'open'
|
547
560
|
->(value) {
|
548
|
-
exit if find_value(value, execute_chosen_found: procname == 'open').fetch(:exit,
|
561
|
+
exit if find_value(value, execute_chosen_found: procname == 'open').fetch(:exit,
|
562
|
+
false)
|
549
563
|
}
|
550
564
|
when 'help'
|
551
565
|
->(_) {
|
@@ -571,9 +585,9 @@ module MarkdownExec
|
|
571
585
|
value.instance_of?(::String) ? (value.chomp != '0') : value
|
572
586
|
}
|
573
587
|
when 'val_as_int'
|
574
|
-
|
588
|
+
lambda(&:to_i)
|
575
589
|
when 'val_as_str'
|
576
|
-
|
590
|
+
lambda(&:to_s)
|
577
591
|
when 'version'
|
578
592
|
lambda { |_|
|
579
593
|
@fout.fout MarkdownExec::VERSION
|
@@ -734,59 +748,26 @@ module MarkdownExec
|
|
734
748
|
@options[:saved_filename_replacement])
|
735
749
|
end
|
736
750
|
|
737
|
-
def select_document_if_multiple(files = list_markdown_files_in_path,
|
751
|
+
def select_document_if_multiple(files = list_markdown_files_in_path,
|
752
|
+
prompt: options[:prompt_select_md].to_s)
|
738
753
|
return files[0] if (count = files.count) == 1
|
739
754
|
|
740
755
|
return unless count >= 2
|
741
756
|
|
742
757
|
opts = options.dup
|
743
|
-
select_option_or_exit(
|
744
|
-
|
745
|
-
opts.merge(per_page: opts[:select_page_height]))
|
746
|
-
end
|
747
|
-
|
748
|
-
# Presents a TTY prompt to select an option or exit, returns selected option or nil
|
749
|
-
def select_option_or_exit(prompt_text, strings, opts = {})
|
750
|
-
result = @options.select_option_with_metadata(prompt_text, strings,
|
751
|
-
opts)
|
752
|
-
### 2024-04-20 what for?
|
753
|
-
# return unless result.fetch(:option, nil)
|
754
|
-
|
755
|
-
result[:selected]
|
756
|
-
end
|
757
|
-
|
758
|
-
def select_recent_output
|
759
|
-
filename = select_option_or_exit(
|
760
|
-
HashDelegator.new(@options).string_send_color(@options[:prompt_select_output].to_s,
|
758
|
+
select_option_or_exit(
|
759
|
+
HashDelegator.new(@options).string_send_color(prompt,
|
761
760
|
:prompt_color_after_script_execution),
|
762
|
-
|
763
|
-
|
764
|
-
@options[:saved_stdout_glob],
|
765
|
-
@options[:list_count]
|
766
|
-
),
|
767
|
-
@options.merge({ per_page: @options[:select_page_height] })
|
761
|
+
files,
|
762
|
+
opts.merge(per_page: opts[:select_page_height])
|
768
763
|
)
|
769
|
-
return unless filename.present?
|
770
|
-
|
771
|
-
`open #{filename} #{options[:output_viewer_options]}`
|
772
764
|
end
|
773
765
|
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
@options[:saved_script_folder],
|
780
|
-
@options[:saved_script_glob],
|
781
|
-
@options[:list_count]
|
782
|
-
),
|
783
|
-
@options.merge({ per_page: @options[:select_page_height] })
|
784
|
-
)
|
785
|
-
return if filename.nil?
|
786
|
-
|
787
|
-
saved_name_split(filename)
|
788
|
-
|
789
|
-
@options.document_inpseq ### ({ save_executed_script: false })
|
766
|
+
# Presents a TTY prompt to select an option or exit, returns selected option or nil
|
767
|
+
def select_option_or_exit(prompt_text, strings, opts = {})
|
768
|
+
@options.select_option_with_metadata(
|
769
|
+
prompt_text, strings, opts
|
770
|
+
)&.fetch(:selected)
|
790
771
|
end
|
791
772
|
|
792
773
|
public
|
@@ -827,4 +808,4 @@ if $PROGRAM_NAME == __FILE__
|
|
827
808
|
assert_equal MenuState::CONTINUE, state
|
828
809
|
end
|
829
810
|
end # module MarkdownExec
|
830
|
-
end
|
811
|
+
end # if
|
data/lib/mdoc.rb
CHANGED
@@ -6,6 +6,8 @@
|
|
6
6
|
require_relative 'block_types'
|
7
7
|
require_relative 'filter'
|
8
8
|
|
9
|
+
$pd = false unless defined?($pd)
|
10
|
+
|
9
11
|
module MarkdownExec
|
10
12
|
##
|
11
13
|
# MDoc represents an imported markdown document.
|
@@ -23,11 +25,11 @@ module MarkdownExec
|
|
23
25
|
#
|
24
26
|
def initialize(table = [])
|
25
27
|
@table = table
|
26
|
-
# &
|
28
|
+
# &bt @table.count
|
27
29
|
end
|
28
30
|
|
29
31
|
def collect_block_code_cann(fcb)
|
30
|
-
body = fcb
|
32
|
+
body = fcb.body.join("\n")
|
31
33
|
xcall = fcb[:cann][1..-2]
|
32
34
|
mstdin = xcall.match(/<(?<type>\$)?(?<name>[A-Za-z_\-.\w]+)/)
|
33
35
|
mstdout = xcall.match(/>(?<type>\$)?(?<name>[A-Za-z_\-.\w]+)/)
|
@@ -44,15 +46,6 @@ module MarkdownExec
|
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
47
|
-
def collect_block_code_shell(fcb)
|
48
|
-
# write named variables to block at top of script
|
49
|
-
#
|
50
|
-
fcb[:body].join(' ').split.compact.map do |key|
|
51
|
-
### format(opts[:block_type_port_set_format], { key: key, value: ENV.fetch(key, nil) })
|
52
|
-
"key: #{key}, value: #{ENV.fetch(key, nil)}"
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
49
|
# Collects and formats the shell command output to redirect script block code to a file or a variable.
|
57
50
|
#
|
58
51
|
# @param [Hash] fcb A hash containing information about the script block's stdout and body.
|
@@ -66,7 +59,7 @@ module MarkdownExec
|
|
66
59
|
# If stdout[:type] is false, the command will write the body to a file.
|
67
60
|
def collect_block_code_stdout(fcb)
|
68
61
|
stdout = fcb[:stdout]
|
69
|
-
body = fcb
|
62
|
+
body = fcb.body.join("\n")
|
70
63
|
if stdout[:type]
|
71
64
|
%(export #{stdout[:name]}=$(cat <<"EOF"\n#{body}\nEOF\n))
|
72
65
|
else
|
@@ -83,35 +76,38 @@ module MarkdownExec
|
|
83
76
|
#
|
84
77
|
def collect_block_dependencies(anyname:)
|
85
78
|
name_block = get_block_by_anyname(anyname)
|
86
|
-
|
79
|
+
if name_block.nil? || name_block.keys.empty?
|
80
|
+
raise "Named code block `#{anyname}` not found. (@#{__LINE__})"
|
81
|
+
end
|
87
82
|
|
88
83
|
nickname = name_block.pub_name
|
89
84
|
|
90
85
|
dependencies = collect_dependencies(nickname)
|
91
|
-
# &
|
86
|
+
# &bt dependencies.count
|
92
87
|
all_dependency_names = collect_unique_names(dependencies).push(nickname).uniq
|
93
|
-
# &
|
88
|
+
# &bt all_dependency_names.count
|
94
89
|
|
95
90
|
# select non-chrome blocks in order of appearance in source documents
|
96
91
|
#
|
97
92
|
blocks = @table.select do |fcb|
|
98
|
-
!fcb.fetch(:chrome, false) && all_dependency_names.include?(fcb.pub_name)
|
93
|
+
# !fcb.fetch(:chrome, false) && all_dependency_names.include?(fcb.pub_name)
|
94
|
+
all_dependency_names.include?(fcb.pub_name)
|
99
95
|
end
|
100
|
-
# &
|
96
|
+
# &bt blocks.count
|
101
97
|
|
102
98
|
## add cann key to blocks, calc unmet_dependencies
|
103
99
|
#
|
104
100
|
unmet_dependencies = all_dependency_names.dup
|
105
101
|
blocks = blocks.map do |fcb|
|
106
102
|
unmet_dependencies.delete(fcb.pub_name) # may not exist if block name is duplicated
|
107
|
-
if (call = fcb
|
103
|
+
if (call = fcb.call)
|
108
104
|
[get_block_by_anyname("[#{call.match(/^%\((\S+) |\)/)[1]}]")
|
109
105
|
.merge({ cann: call })]
|
110
106
|
else
|
111
107
|
[]
|
112
108
|
end + [fcb]
|
113
109
|
end.flatten(1)
|
114
|
-
# &
|
110
|
+
# &bt unmet_dependencies.count
|
115
111
|
|
116
112
|
{ all_dependency_names: all_dependency_names,
|
117
113
|
blocks: blocks,
|
@@ -129,7 +125,7 @@ module MarkdownExec
|
|
129
125
|
block_search = collect_block_dependencies(anyname: anyname)
|
130
126
|
if block_search[:blocks]
|
131
127
|
blocks = collect_wrapped_blocks(block_search[:blocks])
|
132
|
-
# &
|
128
|
+
# &bt blocks.count
|
133
129
|
|
134
130
|
block_search.merge(
|
135
131
|
{ block_names: blocks.map(&:pub_name),
|
@@ -138,20 +134,20 @@ module MarkdownExec
|
|
138
134
|
collect_block_code_cann(fcb)
|
139
135
|
elsif fcb[:stdout]
|
140
136
|
collect_block_code_stdout(fcb)
|
141
|
-
elsif [BlockType::
|
142
|
-
|
137
|
+
elsif [BlockType::OPTS].include? fcb.shell
|
138
|
+
fcb.body # entire body is returned to requesing block
|
139
|
+
elsif [BlockType::LINK,
|
140
|
+
BlockType::VARS].include? fcb.shell
|
141
|
+
nil
|
142
|
+
elsif fcb[:chrome] # for Link blocks like History
|
143
143
|
nil
|
144
|
-
elsif fcb
|
145
|
-
|
144
|
+
elsif fcb.shell == BlockType::PORT
|
145
|
+
generate_env_variable_shell_commands(fcb)
|
146
146
|
elsif label_body
|
147
|
-
|
148
|
-
|
149
|
-
block_source.merge({ block_name: block_name_for_bash_comment }))] +
|
150
|
-
fcb[:body] +
|
151
|
-
[label_format_below && format(label_format_below,
|
152
|
-
block_source.merge({ block_name: block_name_for_bash_comment }))]
|
147
|
+
generate_label_body_code(fcb, block_source, label_format_above,
|
148
|
+
label_format_below)
|
153
149
|
else # raw body
|
154
|
-
fcb
|
150
|
+
fcb.body
|
155
151
|
end
|
156
152
|
end.compact.flatten(1).compact }
|
157
153
|
)
|
@@ -222,10 +218,69 @@ module MarkdownExec
|
|
222
218
|
# . empty chrome between code; edges are same as blanks
|
223
219
|
#
|
224
220
|
select_elements_with_neighbor_conditions(selrows) do |prev_element, current, next_element|
|
225
|
-
!(current[:chrome] && !current
|
221
|
+
!(current[:chrome] && !current.oname.present?) ||
|
222
|
+
!(!prev_element.nil? &&
|
223
|
+
prev_element.shell.present? &&
|
224
|
+
!next_element.nil? &&
|
225
|
+
next_element.shell.present?)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Generates shell code lines to set environment variables named in the body of the given object.
|
230
|
+
# Reads a whitespace-separated list of environment variable names from `fcb.body`,
|
231
|
+
# retrieves their values from the current environment, and constructs shell commands
|
232
|
+
# to set these environment variables.
|
233
|
+
#
|
234
|
+
# @param fcb [Object] An object with a `body` method that returns an array of strings,
|
235
|
+
# where each string is a name of an environment variable.
|
236
|
+
# @return [Array<String>] An array of strings, each representing a shell command to
|
237
|
+
# set an environment variable in the format `KEY=value`.
|
238
|
+
#
|
239
|
+
# Example:
|
240
|
+
# If `fcb.body` returns ["PATH", "HOME"], and the current environment has PATH=/usr/bin
|
241
|
+
# and HOME=/home/user, this method will return:
|
242
|
+
# ["PATH=/usr/bin", "HOME=/home/user"]
|
243
|
+
#
|
244
|
+
def generate_env_variable_shell_commands(fcb)
|
245
|
+
fcb.body.join(' ').split.compact.map do |key|
|
246
|
+
"#{key}=#{Shellwords.escape ENV.fetch(key, '')}"
|
226
247
|
end
|
227
248
|
end
|
228
249
|
|
250
|
+
# Generates a formatted code block with labels above and below the main content.
|
251
|
+
# The labels and content are based on the provided format strings and the body of the given object.
|
252
|
+
#
|
253
|
+
# @param fcb [Object] An object with a `pub_name` method that returns a string, and a `body` method that returns an array of strings.
|
254
|
+
# @param block_source [Hash] A hash containing additional information to be merged into the format strings.
|
255
|
+
# @param label_format_above [String, nil] A format string for the label above the content, or nil if no label is needed.
|
256
|
+
# @param label_format_below [String, nil] A format string for the label below the content, or nil if no label is needed.
|
257
|
+
# @return [Array<String>] An array of strings representing the formatted code block, with optional labels above and below the main content.
|
258
|
+
#
|
259
|
+
# Example:
|
260
|
+
# If `fcb.pub_name` returns "Example Block", `fcb.body` returns ["line1", "line2"],
|
261
|
+
# `block_source` is { source: "source_info" }, `label_format_above` is "Start of %{block_name}",
|
262
|
+
# and `label_format_below` is "End of %{block_name}", the method will return:
|
263
|
+
# ["Start of Example_Block", "line1", "line2", "End of Example_Block"]
|
264
|
+
#
|
265
|
+
def generate_label_body_code(fcb, block_source, label_format_above, label_format_below)
|
266
|
+
block_name_for_bash_comment = fcb.pub_name.gsub(/\s+/, '_')
|
267
|
+
|
268
|
+
label_above = if label_format_above
|
269
|
+
format(label_format_above,
|
270
|
+
block_source.merge({ block_name: block_name_for_bash_comment }))
|
271
|
+
else
|
272
|
+
nil
|
273
|
+
end
|
274
|
+
label_below = if label_format_below
|
275
|
+
format(label_format_below,
|
276
|
+
block_source.merge({ block_name: block_name_for_bash_comment }))
|
277
|
+
else
|
278
|
+
nil
|
279
|
+
end
|
280
|
+
|
281
|
+
[label_above, *fcb.body, label_below].compact
|
282
|
+
end
|
283
|
+
|
229
284
|
# Retrieves a code block by its name.
|
230
285
|
#
|
231
286
|
# @param name [String] The name of the code block to retrieve.
|
@@ -233,10 +288,14 @@ module MarkdownExec
|
|
233
288
|
# @return [Hash] The code block as a hash or the default value if not found.
|
234
289
|
#
|
235
290
|
def get_block_by_anyname(name, default = {})
|
291
|
+
# &bt name
|
236
292
|
@table.select do |fcb|
|
237
|
-
fcb.
|
238
|
-
|
239
|
-
|
293
|
+
fcb.tap { |_ret| pp [__LINE__, 'get_block_by_anyname()', 'fcb', fcb] if $pd }
|
294
|
+
fcb.nickname == name ||
|
295
|
+
fcb.dname == name ||
|
296
|
+
fcb.oname == name ||
|
297
|
+
fcb.pub_name == name
|
298
|
+
end.fetch(0, default).tap { |ret| pp [__LINE__, 'get_block_by_anyname() ->', ret] if $pd }
|
240
299
|
end
|
241
300
|
|
242
301
|
# Checks if a code block should be hidden based on the given options.
|
@@ -250,15 +309,15 @@ module MarkdownExec
|
|
250
309
|
if block.fetch(:chrome, false)
|
251
310
|
false
|
252
311
|
else
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
312
|
+
opts[:hide_blocks_by_name] &&
|
313
|
+
((opts[:block_name_hidden_match]&.present? &&
|
314
|
+
block.oname&.match(Regexp.new(opts[:block_name_hidden_match]))) ||
|
315
|
+
(opts[:block_name_include_match]&.present? &&
|
316
|
+
block.oname&.match(Regexp.new(opts[:block_name_include_match]))) ||
|
317
|
+
(opts[:block_name_wrapper_match]&.present? &&
|
318
|
+
block.oname&.match(Regexp.new(opts[:block_name_wrapper_match])))) &&
|
319
|
+
(block.oname&.present? || block[:label]&.present?)
|
320
|
+
|
262
321
|
end
|
263
322
|
end
|
264
323
|
|
@@ -277,7 +336,7 @@ module MarkdownExec
|
|
277
336
|
next if memo.include? req
|
278
337
|
|
279
338
|
memo += [req]
|
280
|
-
get_block_by_anyname(req).
|
339
|
+
get_block_by_anyname(req).reqs
|
281
340
|
end
|
282
341
|
.compact
|
283
342
|
.flatten(1)
|
@@ -295,9 +354,11 @@ module MarkdownExec
|
|
295
354
|
return memo if memo.keys.include? source
|
296
355
|
|
297
356
|
block = get_block_by_anyname(source)
|
298
|
-
|
357
|
+
if block.nil? || block.keys.empty?
|
358
|
+
raise "Named code block `#{source}` not found. (@#{__LINE__})"
|
359
|
+
end
|
299
360
|
|
300
|
-
memo[source] = block
|
361
|
+
memo[source] = block.reqs
|
301
362
|
return memo unless memo[source]&.count&.positive?
|
302
363
|
|
303
364
|
memo[source].each do |req|
|
@@ -322,11 +383,11 @@ module MarkdownExec
|
|
322
383
|
|
323
384
|
end
|
324
385
|
|
325
|
-
return memo unless block
|
386
|
+
return memo unless block.reqs
|
326
387
|
|
327
|
-
memo[source] = block
|
388
|
+
memo[source] = block.reqs
|
328
389
|
|
329
|
-
block
|
390
|
+
block.reqs.each { |req| collect_dependencies(req, memo) unless memo.key?(req) }
|
330
391
|
memo
|
331
392
|
end
|
332
393
|
|
@@ -364,7 +425,7 @@ module MarkdownExec
|
|
364
425
|
# next_element = array[index + 1]
|
365
426
|
|
366
427
|
# # Check the conditions for property A on the current element and property B on adjacent elements
|
367
|
-
# unless element[:chrome] && !element[:oname].present? && prev_element
|
428
|
+
# unless element[:chrome] && !element[:oname].present? && prev_element.shell.present? && next_element.shell.present?
|
368
429
|
# selected_elements << element
|
369
430
|
# # else
|
370
431
|
# # pp 'SKIPPING', element
|
@@ -512,12 +573,6 @@ if $PROGRAM_NAME == __FILE__
|
|
512
573
|
# Test case 1: blocks with wraps
|
513
574
|
OpenStruct.new(oname: 'block1')
|
514
575
|
|
515
|
-
assert_equal(%w[{wrap1} a],
|
516
|
-
@mdoc.collect_wrapped_blocks(
|
517
|
-
[OpenStruct.new(oname: 'a',
|
518
|
-
wraps: ['{wrap1}'])]
|
519
|
-
).map(&:oname))
|
520
|
-
|
521
576
|
assert_equal(%w[{wrap2-before} {wrap2} b {wrap2-after}],
|
522
577
|
@mdoc.collect_wrapped_blocks(
|
523
578
|
[OpenStruct.new(oname: 'b',
|