markdown_exec 0.2.5 → 1.1.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/CHANGELOG.md +73 -11
- data/Gemfile +6 -5
- data/Gemfile.lock +13 -1
- data/README.md +56 -12
- data/Rakefile +35 -1
- data/assets/approve_code.png +0 -0
- data/assets/output_of_execution.png +0 -0
- data/assets/select_a_block.png +0 -0
- data/assets/select_a_file.png +0 -0
- data/bin/tab_completion.sh +143 -0
- data/bin/tab_completion.sh.erb +85 -0
- data/lib/markdown_exec/version.rb +3 -2
- data/lib/markdown_exec.rb +695 -275
- data/lib/shared.rb +121 -0
- metadata +20 -10
- data/fixtures/bash1.md +0 -12
- data/fixtures/bash2.md +0 -15
- data/fixtures/exclude1.md +0 -6
- data/fixtures/exclude2.md +0 -9
- data/fixtures/exec1.md +0 -8
- data/fixtures/heading1.md +0 -19
- data/fixtures/sample1.md +0 -9
- data/fixtures/title1.md +0 -6
data/lib/markdown_exec.rb
CHANGED
@@ -3,38 +3,14 @@
|
|
3
3
|
|
4
4
|
# encoding=utf-8
|
5
5
|
|
6
|
+
require 'English'
|
7
|
+
require 'clipboard'
|
6
8
|
require 'open3'
|
7
9
|
require 'optparse'
|
8
10
|
require 'tty-prompt'
|
9
11
|
require 'yaml'
|
10
12
|
|
11
|
-
|
12
|
-
# default if nil
|
13
|
-
# false if empty or '0'
|
14
|
-
# else true
|
15
|
-
|
16
|
-
def env_bool(name, default: false)
|
17
|
-
return default if name.nil? || (val = ENV[name]).nil?
|
18
|
-
return false if val.empty? || val == '0'
|
19
|
-
|
20
|
-
true
|
21
|
-
end
|
22
|
-
|
23
|
-
def env_int(name, default: 0)
|
24
|
-
return default if name.nil? || (val = ENV[name]).nil?
|
25
|
-
return default if val.empty?
|
26
|
-
|
27
|
-
val.to_i
|
28
|
-
end
|
29
|
-
|
30
|
-
def env_str(name, default: '')
|
31
|
-
return default if name.nil? || (val = ENV[name]).nil?
|
32
|
-
|
33
|
-
val || default
|
34
|
-
end
|
35
|
-
|
36
|
-
$pdebug = env_bool 'MDE_DEBUG'
|
37
|
-
|
13
|
+
require_relative 'shared'
|
38
14
|
require_relative 'markdown_exec/version'
|
39
15
|
|
40
16
|
$stderr.sync = true
|
@@ -62,27 +38,17 @@ end
|
|
62
38
|
|
63
39
|
public
|
64
40
|
|
65
|
-
#
|
66
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
:to_yaml
|
77
|
-
else
|
78
|
-
:inspect
|
79
|
-
end
|
80
|
-
|
81
|
-
puts "-> #{caller[0].scan(/in `?(\S+)'$/)[0][0]}()" \
|
82
|
-
" #{name}: #{method(fn).call}"
|
83
|
-
|
84
|
-
self
|
85
|
-
end
|
41
|
+
# display_level values
|
42
|
+
DISPLAY_LEVEL_BASE = 0 # required output
|
43
|
+
DISPLAY_LEVEL_ADMIN = 1
|
44
|
+
DISPLAY_LEVEL_DEBUG = 2
|
45
|
+
DISPLAY_LEVEL_DEFAULT = DISPLAY_LEVEL_ADMIN
|
46
|
+
DISPLAY_LEVEL_MAX = DISPLAY_LEVEL_DEBUG
|
47
|
+
|
48
|
+
# @execute_files[ind] = @execute_files[ind] + [block]
|
49
|
+
EF_STDOUT = 0
|
50
|
+
EF_STDERR = 1
|
51
|
+
EF_STDIN = 2
|
86
52
|
|
87
53
|
module MarkdownExec
|
88
54
|
class Error < StandardError; end
|
@@ -101,14 +67,22 @@ module MarkdownExec
|
|
101
67
|
# options necessary to start, parse input, defaults for cli options
|
102
68
|
|
103
69
|
def base_options
|
104
|
-
|
105
|
-
.
|
106
|
-
next unless opt_name.present?
|
107
|
-
|
108
|
-
|
70
|
+
menu_iter do |item|
|
71
|
+
item.tap_inspect name: :item, format: :yaml
|
72
|
+
next unless item[:opt_name].present?
|
73
|
+
|
74
|
+
item_default = item[:default]
|
75
|
+
item_default.tap_inspect name: :item_default
|
76
|
+
value = if item_default.nil?
|
77
|
+
item_default
|
78
|
+
else
|
79
|
+
env_str(item[:env_var], default: value_for_hash(item_default))
|
80
|
+
end
|
81
|
+
[item[:opt_name], item[:proc1] ? item[:proc1].call(value) : value]
|
109
82
|
end.compact.to_h.merge(
|
110
83
|
{
|
111
84
|
mdheadings: true, # use headings (levels 1,2,3) in block lable
|
85
|
+
menu_exit_at_top: true,
|
112
86
|
menu_with_exit: true
|
113
87
|
}
|
114
88
|
).tap_inspect format: :yaml
|
@@ -123,6 +97,7 @@ module MarkdownExec
|
|
123
97
|
prompt_approve_block: 'Process?',
|
124
98
|
prompt_select_block: 'Choose a block:',
|
125
99
|
prompt_select_md: 'Choose a file:',
|
100
|
+
prompt_select_output: 'Choose a file:',
|
126
101
|
saved_script_filename: nil, # calculated
|
127
102
|
struct: true # allow get_block_summary()
|
128
103
|
}
|
@@ -139,13 +114,43 @@ module MarkdownExec
|
|
139
114
|
display_command(opts, required_blocks) if opts[:output_script] || opts[:user_must_approve]
|
140
115
|
|
141
116
|
allow = true
|
142
|
-
|
143
|
-
|
117
|
+
if opts[:user_must_approve]
|
118
|
+
loop do
|
119
|
+
# (sel = @prompt.select(opts[:prompt_approve_block], %w(Yes No Copy_script_to_clipboard Save_script), cycle: true)).tap_inspect name: :sel
|
120
|
+
(sel = @prompt.select(opts[:prompt_approve_block], filter: true) do |menu|
|
121
|
+
menu.default 1
|
122
|
+
# menu.enum '.'
|
123
|
+
# menu.filter true
|
124
|
+
|
125
|
+
menu.choice 'Yes', 1
|
126
|
+
menu.choice 'No', 2
|
127
|
+
menu.choice 'Copy script to clipboard', 3
|
128
|
+
menu.choice 'Save script', 4
|
129
|
+
end).tap_inspect name: :sel
|
130
|
+
allow = (sel == 1)
|
131
|
+
if sel == 3
|
132
|
+
text = required_blocks.flatten.join($INPUT_RECORD_SEPARATOR)
|
133
|
+
Clipboard.copy(text)
|
134
|
+
fout "Clipboard updated: #{required_blocks.count} blocks, #{required_blocks.flatten.count} lines, #{text.length} characters"
|
135
|
+
end
|
136
|
+
if sel == 4
|
137
|
+
# opts[:saved_script_filename] = saved_name_make(opts)
|
138
|
+
write_command_file(opts.merge(save_executed_script: true), required_blocks)
|
139
|
+
fout "File saved: #{@options[:saved_filespec]}"
|
140
|
+
end
|
141
|
+
break if [1, 2].include? sel
|
142
|
+
end
|
143
|
+
end
|
144
|
+
(opts[:ir_approve] = allow).tap_inspect name: :allow
|
145
|
+
|
144
146
|
selected = get_block_by_name blocks_in_file, opts[:block_name]
|
145
147
|
|
146
148
|
if opts[:ir_approve]
|
147
|
-
write_command_file
|
149
|
+
write_command_file opts, required_blocks
|
148
150
|
command_execute opts, required_blocks.flatten.join("\n")
|
151
|
+
save_execution_output
|
152
|
+
output_execution_summary
|
153
|
+
output_execution_result
|
149
154
|
end
|
150
155
|
|
151
156
|
selected[:name]
|
@@ -164,40 +169,45 @@ module MarkdownExec
|
|
164
169
|
@execute_files = Hash.new([])
|
165
170
|
@execute_options = opts
|
166
171
|
@execute_started_at = Time.now.utc
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
until
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
172
|
+
|
173
|
+
Open3.popen3(@options[:shell], '-c', cmd2) do |stdin, stdout, stderr, exec_thr|
|
174
|
+
# pid = exec_thr.pid # pid of the started process
|
175
|
+
|
176
|
+
t1 = Thread.new do
|
177
|
+
until (line = stdout.gets).nil?
|
178
|
+
@execute_files[EF_STDOUT] = @execute_files[EF_STDOUT] + [line]
|
179
|
+
print line if opts[:output_stdout]
|
180
|
+
yield nil, line, nil, exec_thr if block_given?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
t2 = Thread.new do
|
185
|
+
until (line = stderr.gets).nil?
|
186
|
+
@execute_files[EF_STDERR] = @execute_files[EF_STDERR] + [line]
|
187
|
+
print line if opts[:output_stdout]
|
188
|
+
yield nil, nil, line, exec_thr if block_given?
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
in_thr = Thread.new do
|
193
|
+
while exec_thr.alive? # reading input until the child process ends
|
194
|
+
stdin.puts(line = $stdin.gets)
|
195
|
+
@execute_files[EF_STDIN] = @execute_files[EF_STDIN] + [line]
|
196
|
+
yield line, nil, nil, exec_thr if block_given?
|
189
197
|
end
|
190
|
-
rescue IOError => e
|
191
|
-
fout "IOError: #{e}"
|
192
198
|
end
|
193
|
-
|
199
|
+
|
200
|
+
exec_thr.join
|
201
|
+
in_thr.kill
|
202
|
+
# @return_code = exec_thr.value
|
194
203
|
end
|
204
|
+
@execute_completed_at = Time.now.utc
|
195
205
|
rescue Errno::ENOENT => e
|
196
206
|
# error triggered by missing command in script
|
197
207
|
@execute_aborted_at = Time.now.utc
|
198
208
|
@execute_error_message = e.message
|
199
209
|
@execute_error = e
|
200
|
-
@execute_files[
|
210
|
+
@execute_files[EF_STDERR] += [e.message]
|
201
211
|
fout "Error ENOENT: #{e.inspect}"
|
202
212
|
end
|
203
213
|
|
@@ -211,7 +221,9 @@ module MarkdownExec
|
|
211
221
|
end
|
212
222
|
|
213
223
|
def display_command(_opts, required_blocks)
|
224
|
+
fout ' #=#=#'.yellow
|
214
225
|
required_blocks.each { |cb| fout cb }
|
226
|
+
fout ' #=#=#'.yellow
|
215
227
|
end
|
216
228
|
|
217
229
|
def exec_block(options, _block_name = '')
|
@@ -221,41 +233,31 @@ module MarkdownExec
|
|
221
233
|
# document and block reports
|
222
234
|
#
|
223
235
|
files = list_files_per_options(options)
|
224
|
-
if @options[:list_blocks]
|
225
|
-
fout_list (files.map do |file|
|
226
|
-
make_block_labels(filename: file, struct: true)
|
227
|
-
end).flatten(1)
|
228
|
-
return
|
229
|
-
end
|
230
|
-
|
231
|
-
if @options[:list_default_yaml]
|
232
|
-
fout_list list_default_yaml
|
233
|
-
return
|
234
|
-
end
|
235
|
-
|
236
|
-
if @options[:list_docs]
|
237
|
-
fout_list files
|
238
|
-
return
|
239
|
-
end
|
240
|
-
|
241
|
-
if @options[:list_default_env]
|
242
|
-
fout_list list_default_env
|
243
|
-
return
|
244
|
-
end
|
245
236
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
237
|
+
simple_commands = {
|
238
|
+
doc_glob: -> { fout options[:md_filename_glob] },
|
239
|
+
list_blocks: lambda do
|
240
|
+
fout_list (files.map do |file|
|
241
|
+
make_block_labels(filename: file, struct: true)
|
242
|
+
end).flatten(1)
|
243
|
+
end,
|
244
|
+
list_default_yaml: -> { fout_list list_default_yaml },
|
245
|
+
list_docs: -> { fout_list files },
|
246
|
+
list_default_env: -> { fout_list list_default_env },
|
247
|
+
list_recent_output: -> { fout_list list_recent_output },
|
248
|
+
list_recent_scripts: -> { fout_list list_recent_scripts },
|
249
|
+
pwd: -> { fout File.expand_path('..', __dir__) },
|
250
|
+
run_last_script: -> { run_last_script },
|
251
|
+
select_recent_output: -> { select_recent_output },
|
252
|
+
select_recent_script: -> { select_recent_script },
|
253
|
+
tab_completions: -> { fout tab_completions },
|
254
|
+
menu_export: -> { fout menu_export }
|
255
|
+
}
|
256
|
+
simple_commands.each_key do |key|
|
257
|
+
if @options[key]
|
258
|
+
simple_commands[key].call
|
259
|
+
return # rubocop:disable Lint/NonLocalExitFromIterator
|
260
|
+
end
|
259
261
|
end
|
260
262
|
|
261
263
|
# process
|
@@ -266,8 +268,6 @@ module MarkdownExec
|
|
266
268
|
struct: true
|
267
269
|
)
|
268
270
|
fout "saved_filespec: #{@execute_script_filespec}" if @options[:output_saved_script_filename]
|
269
|
-
save_execution_output
|
270
|
-
output_execution_summary
|
271
271
|
end
|
272
272
|
|
273
273
|
# standard output; not for debug
|
@@ -304,6 +304,19 @@ module MarkdownExec
|
|
304
304
|
end
|
305
305
|
end
|
306
306
|
|
307
|
+
def approved_fout?(level)
|
308
|
+
level <= @options[:display_level]
|
309
|
+
end
|
310
|
+
|
311
|
+
# display output at level or lower than filter (DISPLAY_LEVEL_DEFAULT)
|
312
|
+
#
|
313
|
+
def lout(str, level: DISPLAY_LEVEL_BASE)
|
314
|
+
return unless approved_fout? level
|
315
|
+
|
316
|
+
# fout level == DISPLAY_LEVEL_BASE ? str : DISPLAY_LEVEL_XBASE_PREFIX + str
|
317
|
+
fout level == DISPLAY_LEVEL_BASE ? str : @options[:display_level_xbase_prefix] + str
|
318
|
+
end
|
319
|
+
|
307
320
|
def list_blocks_in_file(call_options = {}, &options_block)
|
308
321
|
opts = optsmerge call_options, options_block
|
309
322
|
|
@@ -312,6 +325,11 @@ module MarkdownExec
|
|
312
325
|
exit 1
|
313
326
|
end
|
314
327
|
|
328
|
+
unless File.exist? opts[:filename]
|
329
|
+
fout 'Document is missing.'
|
330
|
+
exit 1
|
331
|
+
end
|
332
|
+
|
315
333
|
fenced_start_and_end_match = Regexp.new opts[:fenced_start_and_end_match]
|
316
334
|
fenced_start_ex = Regexp.new opts[:fenced_start_ex_match]
|
317
335
|
block_title = ''
|
@@ -367,25 +385,23 @@ module MarkdownExec
|
|
367
385
|
end
|
368
386
|
|
369
387
|
def list_default_env
|
370
|
-
|
371
|
-
|
372
|
-
next unless env_var.present?
|
388
|
+
menu_iter do |item|
|
389
|
+
next unless item[:env_var].present?
|
373
390
|
|
374
391
|
[
|
375
|
-
"#{env_var}=#{value_for_cli default}",
|
376
|
-
description.present? ? description : nil
|
392
|
+
"#{item[:env_var]}=#{value_for_cli item[:default]}",
|
393
|
+
item[:description].present? ? item[:description] : nil
|
377
394
|
].compact.join(' # ')
|
378
395
|
end.compact.sort
|
379
396
|
end
|
380
397
|
|
381
398
|
def list_default_yaml
|
382
|
-
|
383
|
-
|
384
|
-
next unless opt_name.present? && default.present?
|
399
|
+
menu_iter do |item|
|
400
|
+
next unless item[:opt_name].present? && item[:default].present?
|
385
401
|
|
386
402
|
[
|
387
|
-
"#{opt_name}: #{value_for_yaml default}",
|
388
|
-
description.present? ? description : nil
|
403
|
+
"#{item[:opt_name]}: #{value_for_yaml item[:default]}",
|
404
|
+
item[:description].present? ? item[:description] : nil
|
389
405
|
].compact.join(' # ')
|
390
406
|
end.compact.sort
|
391
407
|
end
|
@@ -451,9 +467,28 @@ module MarkdownExec
|
|
451
467
|
.tap_inspect
|
452
468
|
end
|
453
469
|
|
470
|
+
def most_recent(arr)
|
471
|
+
return unless arr
|
472
|
+
return if arr.count < 1
|
473
|
+
|
474
|
+
arr.max.tap_inspect
|
475
|
+
end
|
476
|
+
|
477
|
+
def most_recent_list(arr)
|
478
|
+
return unless arr
|
479
|
+
return if (ac = arr.count) < 1
|
480
|
+
|
481
|
+
arr.sort[-[ac, options[:list_count]].min..].reverse.tap_inspect
|
482
|
+
end
|
483
|
+
|
484
|
+
def list_recent_output
|
485
|
+
most_recent_list(Dir.glob(File.join(@options[:saved_stdout_folder],
|
486
|
+
@options[:saved_stdout_glob]))).tap_inspect
|
487
|
+
end
|
488
|
+
|
454
489
|
def list_recent_scripts
|
455
|
-
Dir.glob(File.join(@options[:saved_script_folder],
|
456
|
-
|
490
|
+
most_recent_list(Dir.glob(File.join(@options[:saved_script_folder],
|
491
|
+
@options[:saved_script_glob]))).tap_inspect
|
457
492
|
end
|
458
493
|
|
459
494
|
def make_block_label(block, call_options = {})
|
@@ -475,86 +510,400 @@ module MarkdownExec
|
|
475
510
|
end.compact.tap_inspect
|
476
511
|
end
|
477
512
|
|
478
|
-
def
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
513
|
+
def menu_data1
|
514
|
+
val_as_bool = ->(value) { value.class.to_s == 'String' ? (value.chomp != '0') : value }
|
515
|
+
val_as_int = ->(value) { value.to_i }
|
516
|
+
val_as_str = ->(value) { value.to_s }
|
517
|
+
# val_true = ->(_value) { true } # for commands, sets option to true
|
518
|
+
set1 = [
|
519
|
+
{
|
520
|
+
arg_name: 'PATH',
|
521
|
+
default: '.',
|
522
|
+
description: 'Read configuration file',
|
523
|
+
long_name: 'config',
|
524
|
+
proc1: lambda { |value|
|
525
|
+
read_configuration_file! options, value
|
526
|
+
}
|
527
|
+
},
|
528
|
+
{
|
529
|
+
arg_name: 'BOOL',
|
530
|
+
default: false,
|
531
|
+
description: 'Debug output',
|
532
|
+
env_var: 'MDE_DEBUG',
|
533
|
+
long_name: 'debug',
|
534
|
+
short_name: 'd',
|
535
|
+
proc1: lambda { |value|
|
536
|
+
$pdebug = value.to_i != 0
|
537
|
+
}
|
538
|
+
},
|
539
|
+
{
|
540
|
+
arg_name: "INT.#{DISPLAY_LEVEL_BASE}-#{DISPLAY_LEVEL_MAX}",
|
541
|
+
default: DISPLAY_LEVEL_DEFAULT,
|
542
|
+
description: "Output display level (#{DISPLAY_LEVEL_BASE} to #{DISPLAY_LEVEL_MAX})",
|
543
|
+
env_var: 'MDE_DISPLAY_LEVEL',
|
544
|
+
long_name: 'display-level',
|
545
|
+
opt_name: :display_level,
|
546
|
+
proc1: val_as_int
|
547
|
+
},
|
548
|
+
{
|
549
|
+
arg_name: 'NAME',
|
550
|
+
compreply: false,
|
551
|
+
description: 'Name of block',
|
552
|
+
env_var: 'MDE_BLOCK_NAME',
|
553
|
+
long_name: 'block-name',
|
554
|
+
opt_name: :block_name,
|
555
|
+
short_name: 'f',
|
556
|
+
proc1: val_as_str
|
557
|
+
},
|
558
|
+
{
|
559
|
+
arg_name: 'RELATIVE_PATH',
|
560
|
+
compreply: '.',
|
561
|
+
description: 'Name of document',
|
562
|
+
env_var: 'MDE_FILENAME',
|
563
|
+
long_name: 'filename',
|
564
|
+
opt_name: :filename,
|
565
|
+
short_name: 'f',
|
566
|
+
proc1: val_as_str
|
567
|
+
},
|
568
|
+
{
|
569
|
+
description: 'List blocks',
|
570
|
+
long_name: 'list-blocks',
|
571
|
+
opt_name: :list_blocks,
|
572
|
+
proc1: val_as_bool
|
573
|
+
},
|
574
|
+
{
|
575
|
+
arg_name: 'INT.1-',
|
576
|
+
default: 32,
|
577
|
+
description: 'Max. items to return in list',
|
578
|
+
env_var: 'MDE_LIST_COUNT',
|
579
|
+
long_name: 'list-count',
|
580
|
+
opt_name: :list_count,
|
581
|
+
proc1: val_as_int
|
582
|
+
},
|
583
|
+
{
|
584
|
+
description: 'List default configuration as environment variables',
|
585
|
+
long_name: 'list-default-env',
|
586
|
+
opt_name: :list_default_env
|
587
|
+
},
|
588
|
+
{
|
589
|
+
description: 'List default configuration as YAML',
|
590
|
+
long_name: 'list-default-yaml',
|
591
|
+
opt_name: :list_default_yaml
|
592
|
+
},
|
593
|
+
{
|
594
|
+
description: 'List docs in current folder',
|
595
|
+
long_name: 'list-docs',
|
596
|
+
opt_name: :list_docs,
|
597
|
+
proc1: val_as_bool
|
598
|
+
},
|
599
|
+
{
|
600
|
+
description: 'List recent saved output',
|
601
|
+
long_name: 'list-recent-output',
|
602
|
+
opt_name: :list_recent_output,
|
603
|
+
proc1: val_as_bool
|
604
|
+
},
|
605
|
+
{
|
606
|
+
description: 'List recent saved scripts',
|
607
|
+
long_name: 'list-recent-scripts',
|
608
|
+
opt_name: :list_recent_scripts,
|
609
|
+
proc1: val_as_bool
|
610
|
+
},
|
611
|
+
{
|
612
|
+
arg_name: 'PREFIX',
|
613
|
+
default: MarkdownExec::BIN_NAME,
|
614
|
+
description: 'Name prefix for stdout files',
|
615
|
+
env_var: 'MDE_LOGGED_STDOUT_FILENAME_PREFIX',
|
616
|
+
long_name: 'logged-stdout-filename-prefix',
|
617
|
+
opt_name: :logged_stdout_filename_prefix,
|
618
|
+
proc1: val_as_str
|
619
|
+
},
|
620
|
+
{
|
621
|
+
arg_name: 'BOOL',
|
622
|
+
default: false,
|
623
|
+
description: 'Display summary for execution',
|
624
|
+
env_var: 'MDE_OUTPUT_EXECUTION_SUMMARY',
|
625
|
+
long_name: 'output-execution-summary',
|
626
|
+
opt_name: :output_execution_summary,
|
627
|
+
proc1: val_as_bool
|
628
|
+
},
|
629
|
+
{
|
630
|
+
arg_name: 'BOOL',
|
631
|
+
default: false,
|
632
|
+
description: 'Display script prior to execution',
|
633
|
+
env_var: 'MDE_OUTPUT_SCRIPT',
|
634
|
+
long_name: 'output-script',
|
635
|
+
opt_name: :output_script,
|
636
|
+
proc1: val_as_bool
|
637
|
+
},
|
638
|
+
{
|
639
|
+
arg_name: 'BOOL',
|
640
|
+
default: true,
|
641
|
+
description: 'Display standard output from execution',
|
642
|
+
env_var: 'MDE_OUTPUT_STDOUT',
|
643
|
+
long_name: 'output-stdout',
|
644
|
+
opt_name: :output_stdout,
|
645
|
+
proc1: val_as_bool
|
646
|
+
},
|
647
|
+
{
|
648
|
+
arg_name: 'RELATIVE_PATH',
|
649
|
+
default: '.',
|
650
|
+
description: 'Path to documents',
|
651
|
+
env_var: 'MDE_PATH',
|
652
|
+
long_name: 'path',
|
653
|
+
opt_name: :path,
|
654
|
+
short_name: 'p',
|
655
|
+
proc1: val_as_str
|
656
|
+
},
|
657
|
+
{
|
658
|
+
description: 'Gem home folder',
|
659
|
+
long_name: 'pwd',
|
660
|
+
opt_name: :pwd,
|
661
|
+
proc1: val_as_bool
|
662
|
+
},
|
663
|
+
{
|
664
|
+
description: 'Run most recently saved script',
|
665
|
+
long_name: 'run-last-script',
|
666
|
+
opt_name: :run_last_script,
|
667
|
+
proc1: val_as_bool
|
668
|
+
},
|
669
|
+
{
|
670
|
+
arg_name: 'BOOL',
|
671
|
+
default: false,
|
672
|
+
description: 'Save executed script',
|
673
|
+
env_var: 'MDE_SAVE_EXECUTED_SCRIPT',
|
674
|
+
long_name: 'save-executed-script',
|
675
|
+
opt_name: :save_executed_script,
|
676
|
+
proc1: val_as_bool
|
677
|
+
},
|
678
|
+
{
|
679
|
+
arg_name: 'BOOL',
|
680
|
+
default: false,
|
681
|
+
description: 'Save standard output of the executed script',
|
682
|
+
env_var: 'MDE_SAVE_EXECUTION_OUTPUT',
|
683
|
+
long_name: 'save-execution-output',
|
684
|
+
opt_name: :save_execution_output,
|
685
|
+
proc1: val_as_bool
|
686
|
+
},
|
687
|
+
{
|
688
|
+
arg_name: 'INT',
|
689
|
+
default: 0o755,
|
690
|
+
description: 'chmod for saved scripts',
|
691
|
+
env_var: 'MDE_SAVED_SCRIPT_CHMOD',
|
692
|
+
long_name: 'saved-script-chmod',
|
693
|
+
opt_name: :saved_script_chmod,
|
694
|
+
proc1: val_as_int
|
695
|
+
},
|
696
|
+
{
|
697
|
+
arg_name: 'PREFIX',
|
698
|
+
default: MarkdownExec::BIN_NAME,
|
699
|
+
description: 'Name prefix for saved scripts',
|
700
|
+
env_var: 'MDE_SAVED_SCRIPT_FILENAME_PREFIX',
|
701
|
+
long_name: 'saved-script-filename-prefix',
|
702
|
+
opt_name: :saved_script_filename_prefix,
|
703
|
+
proc1: val_as_str
|
704
|
+
},
|
705
|
+
{
|
706
|
+
arg_name: 'RELATIVE_PATH',
|
707
|
+
default: 'logs',
|
708
|
+
description: 'Saved script folder',
|
709
|
+
env_var: 'MDE_SAVED_SCRIPT_FOLDER',
|
710
|
+
long_name: 'saved-script-folder',
|
711
|
+
opt_name: :saved_script_folder,
|
712
|
+
proc1: val_as_str
|
713
|
+
},
|
714
|
+
{
|
715
|
+
arg_name: 'GLOB',
|
716
|
+
default: 'mde_*.sh',
|
717
|
+
description: 'Glob matching saved scripts',
|
718
|
+
env_var: 'MDE_SAVED_SCRIPT_GLOB',
|
719
|
+
long_name: 'saved-script-glob',
|
720
|
+
opt_name: :saved_script_glob,
|
721
|
+
proc1: val_as_str
|
722
|
+
},
|
723
|
+
{
|
724
|
+
arg_name: 'RELATIVE_PATH',
|
725
|
+
default: 'logs',
|
726
|
+
description: 'Saved stdout folder',
|
727
|
+
env_var: 'MDE_SAVED_STDOUT_FOLDER',
|
728
|
+
long_name: 'saved-stdout-folder',
|
729
|
+
opt_name: :saved_stdout_folder,
|
730
|
+
proc1: val_as_str
|
731
|
+
},
|
732
|
+
{
|
733
|
+
arg_name: 'GLOB',
|
734
|
+
default: 'mde_*.out.txt',
|
735
|
+
description: 'Glob matching saved outputs',
|
736
|
+
env_var: 'MDE_SAVED_STDOUT_GLOB',
|
737
|
+
long_name: 'saved-stdout-glob',
|
738
|
+
opt_name: :saved_stdout_glob,
|
739
|
+
proc1: val_as_str
|
740
|
+
},
|
741
|
+
{
|
742
|
+
description: 'Select and execute a recently saved output',
|
743
|
+
long_name: 'select-recent-output',
|
744
|
+
opt_name: :select_recent_output,
|
745
|
+
proc1: val_as_bool
|
746
|
+
},
|
747
|
+
{
|
748
|
+
description: 'Select and execute a recently saved script',
|
749
|
+
long_name: 'select-recent-script',
|
750
|
+
opt_name: :select_recent_script,
|
751
|
+
proc1: val_as_bool
|
752
|
+
},
|
753
|
+
{
|
754
|
+
description: 'YAML export of menu',
|
755
|
+
long_name: 'menu-export',
|
756
|
+
opt_name: :menu_export,
|
757
|
+
proc1: val_as_bool
|
758
|
+
},
|
759
|
+
{
|
760
|
+
description: 'List tab completions',
|
761
|
+
long_name: 'tab-completions',
|
762
|
+
opt_name: :tab_completions,
|
763
|
+
proc1: val_as_bool
|
764
|
+
},
|
765
|
+
{
|
766
|
+
arg_name: 'BOOL',
|
767
|
+
default: true,
|
768
|
+
description: 'Pause for user to approve script',
|
769
|
+
env_var: 'MDE_USER_MUST_APPROVE',
|
770
|
+
long_name: 'user-must-approve',
|
771
|
+
opt_name: :user_must_approve,
|
772
|
+
proc1: val_as_bool
|
773
|
+
},
|
774
|
+
{
|
775
|
+
description: 'Show current configuration values',
|
776
|
+
short_name: '0',
|
777
|
+
proc1: lambda { |_|
|
778
|
+
options_finalize options
|
779
|
+
fout sorted_keys(options).to_yaml
|
780
|
+
}
|
781
|
+
},
|
782
|
+
{
|
783
|
+
description: 'App help',
|
784
|
+
long_name: 'help',
|
785
|
+
short_name: 'h',
|
786
|
+
proc1: lambda { |_|
|
787
|
+
fout menu_help
|
788
|
+
exit
|
789
|
+
}
|
790
|
+
},
|
791
|
+
{
|
792
|
+
description: "Print the gem's version",
|
793
|
+
long_name: 'version',
|
794
|
+
short_name: 'v',
|
795
|
+
proc1: lambda { |_|
|
796
|
+
fout MarkdownExec::VERSION
|
797
|
+
exit
|
798
|
+
}
|
799
|
+
},
|
800
|
+
{
|
801
|
+
description: 'Exit app',
|
802
|
+
long_name: 'exit',
|
803
|
+
short_name: 'x',
|
804
|
+
proc1: ->(_) { exit }
|
805
|
+
},
|
806
|
+
{
|
807
|
+
default: '^\(.*\)$',
|
808
|
+
description: 'Pattern for blocks to hide from user-selection',
|
809
|
+
env_var: 'MDE_BLOCK_NAME_EXCLUDED_MATCH',
|
810
|
+
opt_name: :block_name_excluded_match,
|
811
|
+
proc1: val_as_str
|
812
|
+
},
|
813
|
+
{
|
814
|
+
default: ':(?<title>\S+)( |$)',
|
815
|
+
env_var: 'MDE_BLOCK_NAME_MATCH',
|
816
|
+
opt_name: :block_name_match,
|
817
|
+
proc1: val_as_str
|
818
|
+
},
|
819
|
+
{
|
820
|
+
default: '\+\S+',
|
821
|
+
env_var: 'MDE_BLOCK_REQUIRED_SCAN',
|
822
|
+
opt_name: :block_required_scan,
|
823
|
+
proc1: val_as_str
|
824
|
+
},
|
825
|
+
{
|
826
|
+
default: '> ',
|
827
|
+
env_var: 'MDE_DISPLAY_LEVEL_XBASE_PREFIX',
|
828
|
+
opt_name: :display_level_xbase_prefix,
|
829
|
+
proc1: val_as_str
|
830
|
+
},
|
831
|
+
{
|
832
|
+
default: '^`{3,}',
|
833
|
+
env_var: 'MDE_FENCED_START_AND_END_MATCH',
|
834
|
+
opt_name: :fenced_start_and_end_match,
|
835
|
+
proc1: val_as_str
|
836
|
+
},
|
837
|
+
{
|
838
|
+
default: '^`{3,}(?<shell>[^`\s]*) *(?<name>.*)$',
|
839
|
+
env_var: 'MDE_FENCED_START_EX_MATCH',
|
840
|
+
opt_name: :fenced_start_ex_match,
|
841
|
+
proc1: val_as_str
|
842
|
+
},
|
843
|
+
{
|
844
|
+
default: '^# *(?<name>[^#]*?) *$',
|
845
|
+
env_var: 'MDE_HEADING1_MATCH',
|
846
|
+
opt_name: :heading1_match,
|
847
|
+
proc1: val_as_str
|
848
|
+
},
|
849
|
+
{
|
850
|
+
default: '^## *(?<name>[^#]*?) *$',
|
851
|
+
env_var: 'MDE_HEADING2_MATCH',
|
852
|
+
opt_name: :heading2_match,
|
853
|
+
proc1: val_as_str
|
854
|
+
},
|
855
|
+
{
|
856
|
+
default: '^### *(?<name>.+?) *$',
|
857
|
+
env_var: 'MDE_HEADING3_MATCH',
|
858
|
+
opt_name: :heading3_match,
|
859
|
+
proc1: val_as_str
|
860
|
+
},
|
861
|
+
{
|
862
|
+
default: '*.[Mm][Dd]',
|
863
|
+
env_var: 'MDE_MD_FILENAME_GLOB',
|
864
|
+
opt_name: :md_filename_glob,
|
865
|
+
proc1: val_as_str
|
866
|
+
},
|
867
|
+
{
|
868
|
+
default: '.+\\.md',
|
869
|
+
env_var: 'MDE_MD_FILENAME_MATCH',
|
870
|
+
opt_name: :md_filename_match,
|
871
|
+
proc1: val_as_str
|
872
|
+
},
|
873
|
+
{
|
874
|
+
description: 'Options for viewing saved output file',
|
875
|
+
env_var: 'MDE_OUTPUT_VIEWER_OPTIONS',
|
876
|
+
opt_name: :output_viewer_options,
|
877
|
+
proc1: val_as_str
|
878
|
+
},
|
879
|
+
{
|
880
|
+
default: 24,
|
881
|
+
description: 'Maximum # of rows in select list',
|
882
|
+
env_var: 'MDE_SELECT_PAGE_HEIGHT',
|
883
|
+
opt_name: :select_page_height,
|
884
|
+
proc1: val_as_int
|
885
|
+
},
|
886
|
+
{
|
887
|
+
default: '#!/usr/bin/env',
|
888
|
+
description: 'Shebang for saved scripts',
|
889
|
+
env_var: 'MDE_SHEBANG',
|
890
|
+
opt_name: :shebang,
|
891
|
+
proc1: val_as_str
|
892
|
+
},
|
893
|
+
{
|
894
|
+
default: 'bash',
|
895
|
+
description: 'Shell for launched scripts',
|
896
|
+
env_var: 'MDE_SHELL',
|
897
|
+
opt_name: :shell,
|
898
|
+
proc1: val_as_str
|
899
|
+
}
|
555
900
|
]
|
901
|
+
# commands first, options second
|
902
|
+
(set1.reject { |v1| v1[:arg_name] }) + (set1.select { |v1| v1[:arg_name] })
|
903
|
+
end
|
556
904
|
|
557
|
-
|
905
|
+
def menu_iter(data = menu_data1, &block)
|
906
|
+
data.map(&block)
|
558
907
|
end
|
559
908
|
|
560
909
|
def menu_help
|
@@ -587,7 +936,8 @@ module MarkdownExec
|
|
587
936
|
|
588
937
|
## position 1: block name (optional)
|
589
938
|
#
|
590
|
-
|
939
|
+
block_name = rest.fetch(1, nil)
|
940
|
+
@options[:block_name] = block_name if block_name.present?
|
591
941
|
end
|
592
942
|
|
593
943
|
def optsmerge(call_options = {}, options_block = nil)
|
@@ -599,6 +949,24 @@ module MarkdownExec
|
|
599
949
|
end.tap_inspect
|
600
950
|
end
|
601
951
|
|
952
|
+
def output_execution_result
|
953
|
+
oq = [['Block', @options[:block_name], DISPLAY_LEVEL_ADMIN],
|
954
|
+
['Command',
|
955
|
+
[MarkdownExec::BIN_NAME,
|
956
|
+
@options[:filename],
|
957
|
+
@options[:block_name]].join(' '),
|
958
|
+
DISPLAY_LEVEL_ADMIN]]
|
959
|
+
|
960
|
+
[['Script', :saved_filespec],
|
961
|
+
['StdOut', :logged_stdout_filespec]].each do |label, name|
|
962
|
+
oq << [label, @options[name], DISPLAY_LEVEL_ADMIN] if @options[name]
|
963
|
+
end
|
964
|
+
|
965
|
+
oq.map do |label, value, level|
|
966
|
+
lout ["#{label}:".yellow, value.to_s].join(' '), level: level
|
967
|
+
end
|
968
|
+
end
|
969
|
+
|
602
970
|
def output_execution_summary
|
603
971
|
return unless @options[:output_execution_summary]
|
604
972
|
|
@@ -616,9 +984,12 @@ module MarkdownExec
|
|
616
984
|
|
617
985
|
def prompt_with_quit(prompt_text, items, opts = {})
|
618
986
|
exit_option = '* Exit'
|
619
|
-
|
620
|
-
|
621
|
-
|
987
|
+
all_items = if @options[:menu_exit_at_top]
|
988
|
+
(@options[:menu_with_exit] ? [exit_option] : []) + items
|
989
|
+
else
|
990
|
+
items + (@options[:menu_with_exit] ? [exit_option] : [])
|
991
|
+
end
|
992
|
+
sel = @prompt.select(prompt_text, all_items, opts.merge(filter: true))
|
622
993
|
sel == exit_option ? nil : sel
|
623
994
|
end
|
624
995
|
|
@@ -662,22 +1033,22 @@ module MarkdownExec
|
|
662
1033
|
opts.banner = [
|
663
1034
|
"#{MarkdownExec::APP_NAME}" \
|
664
1035
|
" - #{MarkdownExec::APP_DESC} (#{MarkdownExec::VERSION})",
|
665
|
-
"Usage: #{executable_name} [path
|
1036
|
+
"Usage: #{executable_name} [(path | filename [block_name])] [options]"
|
666
1037
|
].join("\n")
|
667
1038
|
|
668
|
-
|
669
|
-
|
670
|
-
next unless long_name.present? || short_name.present?
|
1039
|
+
menu_iter do |item|
|
1040
|
+
next unless item[:long_name].present? || item[:short_name].present?
|
671
1041
|
|
672
|
-
opts.on(*[if long_name.present?
|
673
|
-
"--#{long_name}#{arg_name.present? ? " #{arg_name}" : ''}"
|
1042
|
+
opts.on(*[if item[:long_name].present?
|
1043
|
+
"--#{item[:long_name]}#{item[:arg_name].present? ? " #{item[:arg_name]}" : ''}"
|
674
1044
|
end,
|
675
|
-
short_name.present? ? "-#{short_name}" : nil,
|
676
|
-
[description,
|
677
|
-
default.present? ? "[#{value_for_cli default}]" : nil].compact.join(' '),
|
1045
|
+
item[:short_name].present? ? "-#{item[:short_name]}" : nil,
|
1046
|
+
[item[:description],
|
1047
|
+
item[:default].present? ? "[#{value_for_cli item[:default]}]" : nil].compact.join(' '),
|
678
1048
|
lambda { |value|
|
679
|
-
ret = proc1.call(value)
|
680
|
-
|
1049
|
+
# ret = item[:proc1].call(value)
|
1050
|
+
ret = item[:proc1] ? item[:proc1].call(value) : value
|
1051
|
+
options[item[:opt_name]] = ret if item[:opt_name]
|
681
1052
|
ret
|
682
1053
|
}].compact)
|
683
1054
|
end
|
@@ -691,24 +1062,39 @@ module MarkdownExec
|
|
691
1062
|
exec_block options, options[:block_name]
|
692
1063
|
end
|
693
1064
|
|
1065
|
+
FNR11 = '/'
|
1066
|
+
FNR12 = ',~'
|
1067
|
+
|
1068
|
+
def saved_name_make(opts)
|
1069
|
+
fne = opts[:filename].gsub(FNR11, FNR12)
|
1070
|
+
"#{[opts[:saved_script_filename_prefix], Time.now.utc.strftime('%F-%H-%M-%S'), fne,
|
1071
|
+
',', opts[:block_name]].join('_')}.sh"
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
def saved_name_split(name)
|
1075
|
+
mf = name.match(/#{@options[:saved_script_filename_prefix]}_(?<time>[0-9\-]+)_(?<file>.+)_,_(?<block>.+)\.sh/)
|
1076
|
+
return unless mf
|
1077
|
+
|
1078
|
+
@options[:block_name] = mf[:block].tap_inspect name: :options_block_name
|
1079
|
+
@options[:filename] = mf[:file].gsub(FNR12, FNR11).tap_inspect name: :options_filename
|
1080
|
+
end
|
1081
|
+
|
694
1082
|
def run_last_script
|
695
|
-
filename = Dir.glob(File.join(@options[:saved_script_folder],
|
696
|
-
|
697
|
-
|
698
|
-
mf = filename.match(/#{@options[:saved_script_filename_prefix]}_(?<time>[0-9\-]+)_(?<file>.+)_(?<block>.+)\.sh/)
|
1083
|
+
filename = most_recent Dir.glob(File.join(@options[:saved_script_folder],
|
1084
|
+
@options[:saved_script_glob]))
|
1085
|
+
return unless filename
|
699
1086
|
|
700
|
-
|
701
|
-
|
1087
|
+
filename.tap_inspect name: filename
|
1088
|
+
saved_name_split filename
|
702
1089
|
@options[:save_executed_script] = false
|
703
1090
|
select_and_approve_block
|
704
|
-
save_execution_output
|
705
|
-
output_execution_summary
|
706
1091
|
end
|
707
1092
|
|
708
1093
|
def save_execution_output
|
709
1094
|
return unless @options[:save_execution_output]
|
710
1095
|
|
711
1096
|
fne = File.basename(@options[:filename], '.*')
|
1097
|
+
|
712
1098
|
@options[:logged_stdout_filename] =
|
713
1099
|
"#{[@options[:logged_stdout_filename_prefix], Time.now.utc.strftime('%F-%H-%M-%S'), fne,
|
714
1100
|
@options[:block_name]].join('_')}.out.txt"
|
@@ -716,34 +1102,51 @@ module MarkdownExec
|
|
716
1102
|
@logged_stdout_filespec = @options[:logged_stdout_filespec]
|
717
1103
|
dirname = File.dirname(@options[:logged_stdout_filespec])
|
718
1104
|
Dir.mkdir dirname unless File.exist?(dirname)
|
719
|
-
|
720
|
-
# @options[:
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
1105
|
+
|
1106
|
+
# File.write(@options[:logged_stdout_filespec], @execute_files&.fetch(EF_STDOUT, ''))
|
1107
|
+
ol = ["-STDOUT-\n"]
|
1108
|
+
ol += @execute_files&.fetch(EF_STDOUT, [])
|
1109
|
+
ol += ["-STDERR-\n"].tap_inspect name: :ol3
|
1110
|
+
ol += @execute_files&.fetch(EF_STDERR, [])
|
1111
|
+
ol += ["-STDIN-\n"]
|
1112
|
+
ol += @execute_files&.fetch(EF_STDIN, [])
|
1113
|
+
File.write(@options[:logged_stdout_filespec], ol.join)
|
726
1114
|
end
|
727
1115
|
|
728
1116
|
def select_and_approve_block(call_options = {}, &options_block)
|
729
1117
|
opts = optsmerge call_options, options_block
|
730
1118
|
blocks_in_file = list_blocks_in_file(opts.merge(struct: true))
|
731
1119
|
|
732
|
-
|
733
|
-
pt = (opts[:prompt_select_block]).to_s
|
734
|
-
blocks_in_file.each { |block| block.merge! label: make_block_label(block, opts) }
|
735
|
-
block_labels = option_exclude_blocks(opts, blocks_in_file).map { |block| block[:label] }
|
1120
|
+
loop1 = true && !opts[:block_name].present?
|
736
1121
|
|
737
|
-
|
1122
|
+
loop do
|
1123
|
+
unless opts[:block_name].present?
|
1124
|
+
pt = (opts[:prompt_select_block]).to_s
|
1125
|
+
blocks_in_file.each { |block| block.merge! label: make_block_label(block, opts) }
|
1126
|
+
block_labels = option_exclude_blocks(opts, blocks_in_file).map { |block| block[:label] }
|
738
1127
|
|
739
|
-
|
740
|
-
return nil if sel.nil?
|
1128
|
+
return nil if block_labels.count.zero?
|
741
1129
|
|
742
|
-
|
743
|
-
|
744
|
-
end
|
1130
|
+
sel = prompt_with_quit pt, block_labels, per_page: opts[:select_page_height]
|
1131
|
+
return nil if sel.nil?
|
745
1132
|
|
746
|
-
|
1133
|
+
# if sel.nil?
|
1134
|
+
# loop1 = false
|
1135
|
+
# break
|
1136
|
+
# end
|
1137
|
+
|
1138
|
+
label_block = blocks_in_file.select { |block| block[:label] == sel }.fetch(0, nil)
|
1139
|
+
opts[:block_name] = @options[:block_name] = label_block[:name]
|
1140
|
+
|
1141
|
+
end
|
1142
|
+
# if loop1
|
1143
|
+
approve_block opts, blocks_in_file
|
1144
|
+
# end
|
1145
|
+
|
1146
|
+
break unless loop1
|
1147
|
+
|
1148
|
+
opts[:block_name] = ''
|
1149
|
+
end
|
747
1150
|
end
|
748
1151
|
|
749
1152
|
def select_md_file(files_ = nil)
|
@@ -756,22 +1159,25 @@ module MarkdownExec
|
|
756
1159
|
end
|
757
1160
|
end
|
758
1161
|
|
1162
|
+
def select_recent_output
|
1163
|
+
filename = prompt_with_quit @options[:prompt_select_output].to_s, list_recent_output,
|
1164
|
+
per_page: @options[:select_page_height]
|
1165
|
+
return unless filename.present?
|
1166
|
+
|
1167
|
+
`open #{filename} #{options[:output_viewer_options]}`
|
1168
|
+
end
|
1169
|
+
|
759
1170
|
def select_recent_script
|
760
1171
|
filename = prompt_with_quit @options[:prompt_select_md].to_s, list_recent_scripts,
|
761
1172
|
per_page: @options[:select_page_height]
|
762
1173
|
return if filename.nil?
|
763
1174
|
|
764
|
-
|
765
|
-
|
766
|
-
@options[:block_name] = mf[:block]
|
767
|
-
@options[:filename] = "#{mf[:file]}.md" ### other extensions
|
1175
|
+
saved_name_split filename
|
768
1176
|
select_and_approve_block(
|
769
1177
|
bash: true,
|
770
1178
|
save_executed_script: false,
|
771
1179
|
struct: true
|
772
1180
|
)
|
773
|
-
save_execution_output
|
774
|
-
output_execution_summary
|
775
1181
|
end
|
776
1182
|
|
777
1183
|
def sorted_keys(hash1)
|
@@ -782,6 +1188,19 @@ module MarkdownExec
|
|
782
1188
|
{ headings: headings, name: title, title: title }
|
783
1189
|
end
|
784
1190
|
|
1191
|
+
def menu_export(data = menu_data1)
|
1192
|
+
data.map do |item|
|
1193
|
+
item.delete(:proc1)
|
1194
|
+
item
|
1195
|
+
end.to_yaml
|
1196
|
+
end
|
1197
|
+
|
1198
|
+
def tab_completions(data = menu_data1)
|
1199
|
+
data.map do |item|
|
1200
|
+
"--#{item[:long_name]}" if item[:long_name]
|
1201
|
+
end.compact
|
1202
|
+
end
|
1203
|
+
|
785
1204
|
def update_options(opts = {}, over: true)
|
786
1205
|
if over
|
787
1206
|
@options = @options.merge opts
|
@@ -791,19 +1210,6 @@ module MarkdownExec
|
|
791
1210
|
@options.tap_inspect format: :yaml
|
792
1211
|
end
|
793
1212
|
|
794
|
-
def value_for_cli(value)
|
795
|
-
case value.class.to_s
|
796
|
-
when 'String'
|
797
|
-
"'#{value}'"
|
798
|
-
when 'FalseClass', 'TrueClass'
|
799
|
-
value ? '1' : '0'
|
800
|
-
when 'Integer'
|
801
|
-
value
|
802
|
-
else
|
803
|
-
value.to_s
|
804
|
-
end
|
805
|
-
end
|
806
|
-
|
807
1213
|
def value_for_hash(value, default = nil)
|
808
1214
|
return default if value.nil?
|
809
1215
|
|
@@ -835,19 +1241,33 @@ module MarkdownExec
|
|
835
1241
|
end
|
836
1242
|
|
837
1243
|
def write_command_file(opts, required_blocks)
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
1244
|
+
return unless opts[:save_executed_script]
|
1245
|
+
|
1246
|
+
opts[:saved_script_filename] = saved_name_make(opts)
|
1247
|
+
@execute_script_filespec =
|
1248
|
+
@options[:saved_filespec] =
|
1249
|
+
File.join opts[:saved_script_folder], opts[:saved_script_filename]
|
1250
|
+
|
844
1251
|
dirname = File.dirname(@options[:saved_filespec])
|
845
1252
|
Dir.mkdir dirname unless File.exist?(dirname)
|
846
|
-
|
1253
|
+
(shebang = if @options[:shebang]&.present?
|
1254
|
+
"#{@options[:shebang]} #{@options[:shell]}\n"
|
1255
|
+
else
|
1256
|
+
''
|
1257
|
+
end
|
1258
|
+
).tap_inspect name: :shebang
|
1259
|
+
File.write(@options[:saved_filespec], shebang +
|
847
1260
|
"# file_name: #{opts[:filename]}\n" \
|
848
1261
|
"# block_name: #{opts[:block_name]}\n" \
|
849
1262
|
"# time: #{Time.now.utc}\n" \
|
850
1263
|
"#{required_blocks.flatten.join("\n")}\n")
|
1264
|
+
|
1265
|
+
@options[:saved_script_chmod].tap_inspect name: :@options_saved_script_chmod
|
1266
|
+
return if @options[:saved_script_chmod].zero?
|
1267
|
+
|
1268
|
+
@options[:saved_script_chmod].tap_inspect name: :@options_saved_script_chmod
|
1269
|
+
File.chmod @options[:saved_script_chmod], @options[:saved_filespec]
|
1270
|
+
@options[:saved_script_chmod].tap_inspect name: :@options_saved_script_chmod
|
851
1271
|
end
|
852
1272
|
end
|
853
1273
|
end
|