markdown_exec 2.0.8.3 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -9
- data/Gemfile.lock +1 -1
- data/bin/tab_completion.sh +2 -2
- data/examples/data-files.md +50 -0
- data/examples/opts_output_execution.md +46 -0
- data/examples/save.md +7 -0
- data/lib/constants.rb +1 -0
- data/lib/hash_delegator.rb +162 -160
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/mdoc.rb +11 -0
- data/lib/menu.src.yml +42 -8
- data/lib/menu.yml +37 -1
- data/lib/saved_assets.rb +117 -11
- data/lib/streams_out.rb +36 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f49177c09809e5635f448181166f2fe60dffe9b942f1c23eeb29b2ecd43b55a8
|
4
|
+
data.tar.gz: 43488e384c44c757e1c7b95ad68e755a60a5bd617f3532c4e3213604984097e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c923456c84259f80f53a839d48d4ed54c91f3bdc3ddb06fb96a1014b79a4640f21eed0bdb1f58635869fa70a5fb786259745a6e2a46cba2780a0093b81bc3e9
|
7
|
+
data.tar.gz: fbccdda04147b4a9ac0c9dd31bff501a626c60112fd70d0554aa89d2e005494e755abc0f63714c417e25461da23de3a960478cc1dd65fef9c126e927b6bbf037
|
data/CHANGELOG.md
CHANGED
@@ -1,14 +1,23 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
## [2.1.0] - 2024-07-15
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- Option to toggle the output of an execution report.
|
8
|
+
- Option to toggle a menu entry to view saved script and output files.
|
9
|
+
- Options for formatting and parsing saved script and output file names.
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
- Fix handling of output streams for executed scripts to improve logging out output and addition to inherited code.
|
14
|
+
- YAML blocks are not executable from the menu.
|
15
|
+
- Fix collection of output of Link blocks.
|
16
|
+
- Pass-through arguments after "--" to the script.
|
17
|
+
- Remove app info from menu.yml.
|
18
|
+
- Remove test for unwanted arguments.
|
19
|
+
- Fix Link next_block_name when filename is used.
|
20
|
+
- In example doc, use nicknames to allow block content to be displayed.
|
12
21
|
|
13
22
|
## [2.0.8] - 2024-06-05
|
14
23
|
|
data/Gemfile.lock
CHANGED
data/bin/tab_completion.sh
CHANGED
@@ -13,7 +13,7 @@ __filedirs_all()
|
|
13
13
|
}
|
14
14
|
|
15
15
|
_mde_echo_version() {
|
16
|
-
echo "2.0
|
16
|
+
echo "2.1.0"
|
17
17
|
}
|
18
18
|
|
19
19
|
_mde() {
|
@@ -178,4 +178,4 @@ _mde() {
|
|
178
178
|
|
179
179
|
complete -o filenames -o nospace -F _mde mde
|
180
180
|
# _mde_echo_version
|
181
|
-
# echo "Updated: 2024-
|
181
|
+
# echo "Updated: 2024-07-16 20:54:59 UTC"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Demonstrate data blocks
|
2
|
+
|
3
|
+
```opts :(document_options)
|
4
|
+
pause_after_script_execution: true
|
5
|
+
```
|
6
|
+
|
7
|
+
## Create a data file by requiring a YAML block.
|
8
|
+
::: YAML into a file
|
9
|
+
/ YAML block that loads data into a file.
|
10
|
+
```yaml :(test1) >test1.yml
|
11
|
+
a: species
|
12
|
+
b: genus
|
13
|
+
```
|
14
|
+
This is a Bash block that
|
15
|
+
- requires a hidden YAML block (that creates a file), and
|
16
|
+
- displays the file.
|
17
|
+
```bash +(test1)
|
18
|
+
echo "- The data file created"
|
19
|
+
ls -al *.yml
|
20
|
+
echo -e "\n- Contents of the file"
|
21
|
+
cat -n test1.yml
|
22
|
+
echo -e "\n- Remove the data file"
|
23
|
+
rm test1.yml
|
24
|
+
```
|
25
|
+
|
26
|
+
## Load data by requiring a yaml block.
|
27
|
+
::: YAML into a shell variable
|
28
|
+
/ YAML block that loads data into a variable.
|
29
|
+
```yaml :(test2) >$test2
|
30
|
+
c: family
|
31
|
+
d: order
|
32
|
+
```
|
33
|
+
This is a Bash block that
|
34
|
+
- requires a hidden YAML block (that sets a variable), and
|
35
|
+
- displays the variable.
|
36
|
+
```bash +(test2)
|
37
|
+
echo 'data:'
|
38
|
+
echo "$test2"
|
39
|
+
```
|
40
|
+
|
41
|
+
## Visible YAML block that is not executable.
|
42
|
+
::: Non-interactive data
|
43
|
+
```yaml
|
44
|
+
e: class
|
45
|
+
f: phylum
|
46
|
+
```
|
47
|
+
|
48
|
+
# Related MDE options
|
49
|
+
block_stdin_scan | Match to place block body into a file or a variable
|
50
|
+
block_stdout_scan | Match to place block body into a file or a variable
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Demo options: output_execution_report, output_execution_summary
|
2
|
+
|
3
|
+
::: Options are initially True
|
4
|
+
```opts :(document_options) +[document_options]
|
5
|
+
output_execution_report: true
|
6
|
+
output_execution_summary: true
|
7
|
+
pause_after_script_execution: true
|
8
|
+
```
|
9
|
+
```bash
|
10
|
+
whoami
|
11
|
+
pwd >&2
|
12
|
+
date >&1 1>&2
|
13
|
+
```
|
14
|
+
|
15
|
+
## output_execution_report
|
16
|
+
### Example
|
17
|
+
-^-
|
18
|
+
Command: mde ./examples/opt_output_execution_summary.md
|
19
|
+
StdOut: logs/mde_2024-07-08-03-21-59_opt_output_execution_summary_,_whoami___pwd__&2___date__&1_1_&2_.out.txt
|
20
|
+
-v-
|
21
|
+
### Toggle
|
22
|
+
```opts
|
23
|
+
output_execution_report: false
|
24
|
+
```
|
25
|
+
```opts
|
26
|
+
output_execution_report: true
|
27
|
+
```
|
28
|
+
|
29
|
+
## output_execution_summary
|
30
|
+
### Example (edited)
|
31
|
+
:execute_aborted_at:
|
32
|
+
:execute_completed_at: 2024-07-08 03:21:59.988451000 Z
|
33
|
+
:execute_error:
|
34
|
+
:execute_error_message:
|
35
|
+
:execute_options: { ... }
|
36
|
+
:execute_started_at: 2024-07-08 03:21:59.864442000 Z
|
37
|
+
:saved_filespec:
|
38
|
+
:script_block_name:
|
39
|
+
:streamed_lines: { ... }
|
40
|
+
### Toggle
|
41
|
+
```opts
|
42
|
+
output_execution_summary: false
|
43
|
+
```
|
44
|
+
```opts
|
45
|
+
output_execution_summary: true
|
46
|
+
```
|
data/examples/save.md
ADDED
data/lib/constants.rb
CHANGED
data/lib/hash_delegator.rb
CHANGED
@@ -34,6 +34,7 @@ require_relative 'mdoc'
|
|
34
34
|
require_relative 'regexp'
|
35
35
|
require_relative 'resize_terminal'
|
36
36
|
require_relative 'std_out_err_logger'
|
37
|
+
require_relative 'streams_out'
|
37
38
|
require_relative 'string_util'
|
38
39
|
|
39
40
|
class String
|
@@ -163,15 +164,6 @@ module HashDelegatorSelf
|
|
163
164
|
# end.join("\n")
|
164
165
|
# end
|
165
166
|
|
166
|
-
# Formats and returns the execution streams (like stdin, stdout, stderr) for a given key.
|
167
|
-
# It concatenates the array of strings found under the specified key in the run_state's files.
|
168
|
-
#
|
169
|
-
# @param key [Symbol] The key corresponding to the desired execution stream.
|
170
|
-
# @return [String] A concatenated string of the execution stream's contents.
|
171
|
-
def format_execution_streams(key, files = {})
|
172
|
-
(files || {}).fetch(key, []).join
|
173
|
-
end
|
174
|
-
|
175
167
|
# Indents all lines in a given string with a specified indentation string.
|
176
168
|
# @param body [String] A multi-line string to be indented.
|
177
169
|
# @param indent [String] The string used for indentation (default is an empty string).
|
@@ -266,16 +258,6 @@ module HashDelegatorSelf
|
|
266
258
|
exit 1
|
267
259
|
end
|
268
260
|
|
269
|
-
# # Evaluates the given string as Ruby code and rescues any StandardErrors.
|
270
|
-
# # If an error occurs, it calls the error_handler method with 'safeval'.
|
271
|
-
# # @param str [String] The string to be evaluated.
|
272
|
-
# # @return [Object] The result of evaluating the string.
|
273
|
-
# def safeval(str)
|
274
|
-
# eval(str)
|
275
|
-
# rescue StandardError # catches NameError, StandardError
|
276
|
-
# error_handler('safeval')
|
277
|
-
# end
|
278
|
-
|
279
261
|
def set_file_permissions(file_path, chmod_value)
|
280
262
|
File.chmod(chmod_value, file_path)
|
281
263
|
end
|
@@ -309,21 +291,6 @@ module HashDelegatorSelf
|
|
309
291
|
&block)
|
310
292
|
end
|
311
293
|
|
312
|
-
def write_execution_output_to_file(files, filespec)
|
313
|
-
FileUtils.mkdir_p File.dirname(filespec)
|
314
|
-
|
315
|
-
File.write(
|
316
|
-
filespec,
|
317
|
-
["-STDOUT-\n",
|
318
|
-
format_execution_streams(ExecutionStreams::STD_OUT, files),
|
319
|
-
"-STDERR-\n",
|
320
|
-
format_execution_streams(ExecutionStreams::STD_ERR, files),
|
321
|
-
"-STDIN-\n",
|
322
|
-
format_execution_streams(ExecutionStreams::STD_IN, files),
|
323
|
-
"\n"].join
|
324
|
-
)
|
325
|
-
end
|
326
|
-
|
327
294
|
# Yields a line as a new block if the selected message type includes :line.
|
328
295
|
# @param [String] line The line to be processed.
|
329
296
|
# @param [Array<Symbol>] selected_messages A list of message types to check.
|
@@ -587,6 +554,9 @@ module MarkdownExec
|
|
587
554
|
when MenuState::EXIT
|
588
555
|
option_name = @delegate_object[:menu_option_exit_name]
|
589
556
|
insert_at_top = @delegate_object[:menu_exit_at_top]
|
557
|
+
when MenuState::HISTORY
|
558
|
+
option_name = @delegate_object[:menu_option_history_name]
|
559
|
+
insert_at_top = @delegate_object[:menu_load_at_top]
|
590
560
|
when MenuState::LOAD
|
591
561
|
option_name = @delegate_object[:menu_option_load_name]
|
592
562
|
insert_at_top = @delegate_object[:menu_load_at_top]
|
@@ -599,6 +569,8 @@ module MarkdownExec
|
|
599
569
|
when MenuState::VIEW
|
600
570
|
option_name = @delegate_object[:menu_option_view_name]
|
601
571
|
insert_at_top = @delegate_object[:menu_load_at_top]
|
572
|
+
else
|
573
|
+
raise "Missing MenuState: #{menu_state}"
|
602
574
|
end
|
603
575
|
|
604
576
|
formatted_name = format(@delegate_object[:menu_link_format],
|
@@ -726,11 +698,12 @@ module MarkdownExec
|
|
726
698
|
return unless @delegate_object[:saved_stdout_folder]
|
727
699
|
|
728
700
|
@delegate_object[:logged_stdout_filename] =
|
729
|
-
SavedAsset.
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
701
|
+
SavedAsset.new(blockname: block_name,
|
702
|
+
filename: @delegate_object[:filename],
|
703
|
+
prefix: @delegate_object[:logged_stdout_filename_prefix],
|
704
|
+
time: Time.now.utc,
|
705
|
+
exts: '.out.txt',
|
706
|
+
saved_asset_format: @delegate_object[:saved_asset_format]).generate_name
|
734
707
|
|
735
708
|
@logged_stdout_filespec =
|
736
709
|
@delegate_object[:logged_stdout_filespec] =
|
@@ -793,7 +766,7 @@ module MarkdownExec
|
|
793
766
|
end
|
794
767
|
|
795
768
|
def command_execute(command, args: [])
|
796
|
-
@run_state.files =
|
769
|
+
@run_state.files = StreamsOut.new
|
797
770
|
@run_state.options = @delegate_object
|
798
771
|
@run_state.started_at = Time.now.utc
|
799
772
|
|
@@ -807,7 +780,6 @@ module MarkdownExec
|
|
807
780
|
command_execute_in_own_window_format_arguments(rest: args ? args.join(' ') : '')
|
808
781
|
)
|
809
782
|
)
|
810
|
-
|
811
783
|
else
|
812
784
|
@run_state.in_own_window = false
|
813
785
|
execute_command_with_streams(
|
@@ -821,14 +793,14 @@ module MarkdownExec
|
|
821
793
|
@run_state.aborted_at = Time.now.utc
|
822
794
|
@run_state.error_message = err.message
|
823
795
|
@run_state.error = err
|
824
|
-
@run_state.files
|
796
|
+
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR, @run_state.error_message)
|
825
797
|
@fout.fout "Error ENOENT: #{err.inspect}"
|
826
798
|
rescue SignalException => err
|
827
799
|
# Handle SignalException
|
828
800
|
@run_state.aborted_at = Time.now.utc
|
829
801
|
@run_state.error_message = 'SIGTERM'
|
830
802
|
@run_state.error = err
|
831
|
-
@run_state.files
|
803
|
+
@run_state.files.append_stream_line(ExecutionStreams::STD_ERR, @run_state.error_message)
|
832
804
|
@fout.fout "Error ENOENT: #{err.inspect}"
|
833
805
|
end
|
834
806
|
|
@@ -1081,8 +1053,7 @@ module MarkdownExec
|
|
1081
1053
|
return unless @delegate_object[:save_execution_output]
|
1082
1054
|
return if @run_state.in_own_window
|
1083
1055
|
|
1084
|
-
|
1085
|
-
@delegate_object[:logged_stdout_filespec])
|
1056
|
+
@run_state.files.write_execution_output_to_file(@delegate_object[:logged_stdout_filespec])
|
1086
1057
|
end
|
1087
1058
|
|
1088
1059
|
# Select and execute a code block from a Markdown document.
|
@@ -1097,7 +1068,6 @@ module MarkdownExec
|
|
1097
1068
|
block_name: @delegate_object[:block_name],
|
1098
1069
|
document_filename: @delegate_object[:filename]
|
1099
1070
|
)
|
1100
|
-
# @dml_link_state_block_name_from_cli = @dml_link_state.block_name.present? ###
|
1101
1071
|
@run_state.block_name_from_cli = @dml_link_state.block_name.present?
|
1102
1072
|
@cli_block_name = @dml_link_state.block_name
|
1103
1073
|
@dml_now_using_cli = @run_state.block_name_from_cli
|
@@ -1119,12 +1089,14 @@ module MarkdownExec
|
|
1119
1089
|
pop_add_current_code_to_head_and_trigger_load(@dml_link_state, inherited_block_names, code_lines, inherited_dependencies, selected)
|
1120
1090
|
end
|
1121
1091
|
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1092
|
+
fdo = ->(mo) { format(@delegate_object[:menu_link_format], HashDelegator.safeval(@delegate_object[mo])) }
|
1093
|
+
item_back = fdo.call(:menu_option_back_name)
|
1094
|
+
item_edit = fdo.call(:menu_option_edit_name)
|
1095
|
+
item_history = fdo.call(:menu_option_history_name)
|
1096
|
+
item_load = fdo.call(:menu_option_load_name)
|
1097
|
+
item_save = fdo.call(:menu_option_save_name)
|
1098
|
+
item_shell = fdo.call(:menu_option_shell_name)
|
1099
|
+
item_view = fdo.call(:menu_option_view_name)
|
1128
1100
|
|
1129
1101
|
@run_state.batch_random = Random.new.rand
|
1130
1102
|
@run_state.batch_index = 0
|
@@ -1138,6 +1110,12 @@ module MarkdownExec
|
|
1138
1110
|
# puts "@ - parse document #{data}"
|
1139
1111
|
inpseq_parse_document(data)
|
1140
1112
|
|
1113
|
+
if @delegate_object[:menu_for_history]
|
1114
|
+
history_files.tap do |files|
|
1115
|
+
menu_enable_option(item_history, files.count, 'files', menu_state: MenuState::HISTORY) if files.count.positive?
|
1116
|
+
end
|
1117
|
+
end
|
1118
|
+
|
1141
1119
|
if @delegate_object[:menu_for_saved_lines] && @delegate_object[:document_saved_lines_glob].present?
|
1142
1120
|
|
1143
1121
|
sf = document_name_in_glob_as_file_name(@dml_link_state.document_filename, @delegate_object[:document_saved_lines_glob])
|
@@ -1148,11 +1126,11 @@ module MarkdownExec
|
|
1148
1126
|
|
1149
1127
|
# add menu items (glob, load, save) and enable selectively
|
1150
1128
|
menu_add_disabled_option(sf) if files.count.positive? || lines_count.positive?
|
1151
|
-
menu_enable_option(
|
1152
|
-
menu_enable_option(
|
1153
|
-
menu_enable_option(
|
1154
|
-
menu_enable_option(
|
1155
|
-
menu_enable_option(
|
1129
|
+
menu_enable_option(item_load, files.count, 'files', menu_state: MenuState::LOAD) if files.count.positive?
|
1130
|
+
menu_enable_option(item_edit, lines_count, 'lines', menu_state: MenuState::EDIT) if lines_count.positive?
|
1131
|
+
menu_enable_option(item_save, 1, '', menu_state: MenuState::SAVE) if lines_count.positive?
|
1132
|
+
menu_enable_option(item_view, 1, '', menu_state: MenuState::VIEW) if lines_count.positive?
|
1133
|
+
menu_enable_option(item_shell, 1, '', menu_state: MenuState::SHELL) if @delegate_object[:menu_with_shell]
|
1156
1134
|
end
|
1157
1135
|
|
1158
1136
|
when :display_menu
|
@@ -1197,6 +1175,42 @@ module MarkdownExec
|
|
1197
1175
|
debounce_reset
|
1198
1176
|
edited = edit_text(@dml_link_state.inherited_lines.join("\n"))
|
1199
1177
|
@dml_link_state.inherited_lines = edited.split("\n") if edited
|
1178
|
+
|
1179
|
+
return :break if pause_user_exit
|
1180
|
+
|
1181
|
+
InputSequencer.next_link_state(prior_block_was_link: true)
|
1182
|
+
|
1183
|
+
when item_history
|
1184
|
+
debounce_reset
|
1185
|
+
files = history_files
|
1186
|
+
files_table_rows = files.map do |file|
|
1187
|
+
if Regexp.new(@delegate_object[:saved_asset_match]) =~ file
|
1188
|
+
OpenStruct.new(file: file, row: [$~[:time], $~[:blockname], $~[:exts]].join(' '))
|
1189
|
+
else
|
1190
|
+
warn "Cannot parse name: #{file}"
|
1191
|
+
next
|
1192
|
+
end
|
1193
|
+
end.compact
|
1194
|
+
|
1195
|
+
case (name = prompt_select_code_filename(
|
1196
|
+
[@delegate_object[:prompt_filespec_back]] +
|
1197
|
+
files_table_rows.map(&:row),
|
1198
|
+
string: @delegate_object[:prompt_select_history_file],
|
1199
|
+
color_sym: :prompt_color_after_script_execution
|
1200
|
+
))
|
1201
|
+
when @delegate_object[:prompt_filespec_back]
|
1202
|
+
# do nothing
|
1203
|
+
else
|
1204
|
+
file = files_table_rows.select { |ftr| ftr.row == name }&.first
|
1205
|
+
info = file_info(file.file)
|
1206
|
+
warn "#{file.file} - #{info[:lines]} lines / #{info[:size]} bytes"
|
1207
|
+
warn(File.readlines(file.file, chomp: false).map.with_index do |line, ind|
|
1208
|
+
format(' %s. %s', format('% 4d', ind).violet, line)
|
1209
|
+
end)
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
return :break if pause_user_exit
|
1213
|
+
|
1200
1214
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1201
1215
|
|
1202
1216
|
when item_load
|
@@ -1207,6 +1221,9 @@ module MarkdownExec
|
|
1207
1221
|
@dml_link_state.inherited_lines ||= []
|
1208
1222
|
@dml_link_state.inherited_lines += File.readlines(load_filespec, chomp: true)
|
1209
1223
|
end
|
1224
|
+
|
1225
|
+
return :break if pause_user_exit
|
1226
|
+
|
1210
1227
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1211
1228
|
|
1212
1229
|
when item_save
|
@@ -1220,6 +1237,7 @@ module MarkdownExec
|
|
1220
1237
|
return :break
|
1221
1238
|
|
1222
1239
|
end
|
1240
|
+
|
1223
1241
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1224
1242
|
|
1225
1243
|
when item_shell
|
@@ -1238,11 +1256,17 @@ module MarkdownExec
|
|
1238
1256
|
warn "#{'ERR'.bred} #{exit_status}"
|
1239
1257
|
end
|
1240
1258
|
end
|
1259
|
+
|
1260
|
+
return :break if pause_user_exit
|
1261
|
+
|
1241
1262
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1242
1263
|
|
1243
1264
|
when item_view
|
1244
1265
|
debounce_reset
|
1245
1266
|
warn @dml_link_state.inherited_lines.join("\n")
|
1267
|
+
|
1268
|
+
return :break if pause_user_exit
|
1269
|
+
|
1246
1270
|
InputSequencer.next_link_state(prior_block_was_link: true)
|
1247
1271
|
|
1248
1272
|
else
|
@@ -1482,7 +1506,6 @@ module MarkdownExec
|
|
1482
1506
|
# @param mdoc [YourMDocClass] An instance of the MDoc class.
|
1483
1507
|
#
|
1484
1508
|
def execute_shell_type(selected:, mdoc:, block_source:, link_state: LinkState.new)
|
1485
|
-
# binding.irb
|
1486
1509
|
if selected.fetch(:shell, '') == BlockType::LINK
|
1487
1510
|
debounce_reset
|
1488
1511
|
push_link_history_and_trigger_load(link_block_body: selected.fetch(:body, ''),
|
@@ -1561,6 +1584,21 @@ module MarkdownExec
|
|
1561
1584
|
string_send_color(data_string, color_sym)
|
1562
1585
|
end
|
1563
1586
|
|
1587
|
+
# size of a file in bytes and the number of lines
|
1588
|
+
def file_info(file_path)
|
1589
|
+
file_size = 0
|
1590
|
+
line_count = 0
|
1591
|
+
|
1592
|
+
File.open(file_path, 'r') do |file|
|
1593
|
+
file.each_line do |_line|
|
1594
|
+
line_count += 1
|
1595
|
+
end
|
1596
|
+
file_size = file.size
|
1597
|
+
end
|
1598
|
+
|
1599
|
+
{ size: file_size, lines: line_count }
|
1600
|
+
end
|
1601
|
+
|
1564
1602
|
def format_and_execute_command(code_lines:)
|
1565
1603
|
formatted_command = code_lines.flatten.join("\n")
|
1566
1604
|
@fout.fout fetch_color(data_sym: :script_execution_head,
|
@@ -1621,11 +1659,6 @@ module MarkdownExec
|
|
1621
1659
|
bm = extract_named_captures_from_option(titlexcall,
|
1622
1660
|
@delegate_object[:block_name_match])
|
1623
1661
|
|
1624
|
-
fcb.stdin = extract_named_captures_from_option(titlexcall,
|
1625
|
-
@delegate_object[:block_stdin_scan])
|
1626
|
-
fcb.stdout = extract_named_captures_from_option(titlexcall,
|
1627
|
-
@delegate_object[:block_stdout_scan])
|
1628
|
-
|
1629
1662
|
shell_color_option = SHELL_COLOR_OPTIONS[fcb[:shell]]
|
1630
1663
|
|
1631
1664
|
if @delegate_object[:block_name_nick_match].present? && fcb.oname =~ Regexp.new(@delegate_object[:block_name_nick_match])
|
@@ -1662,7 +1695,7 @@ module MarkdownExec
|
|
1662
1695
|
Thread.new do
|
1663
1696
|
stream.each_line do |line|
|
1664
1697
|
line.strip!
|
1665
|
-
@run_state.files
|
1698
|
+
@run_state.files.append_stream_line(file_type, line) if @run_state.files.streams
|
1666
1699
|
|
1667
1700
|
if @delegate_object[:output_stdout]
|
1668
1701
|
# print line
|
@@ -1679,6 +1712,16 @@ module MarkdownExec
|
|
1679
1712
|
end
|
1680
1713
|
end
|
1681
1714
|
|
1715
|
+
def history_files
|
1716
|
+
Dir.glob(
|
1717
|
+
File.join(
|
1718
|
+
@delegate_object[:saved_script_folder],
|
1719
|
+
SavedAsset.new(filename: @delegate_object[:filename],
|
1720
|
+
saved_asset_format: @delegate_object[:saved_asset_format]).generate_name
|
1721
|
+
)
|
1722
|
+
)
|
1723
|
+
end
|
1724
|
+
|
1682
1725
|
# Initializes variables for regex and other states
|
1683
1726
|
def initial_state
|
1684
1727
|
{
|
@@ -1760,7 +1803,7 @@ module MarkdownExec
|
|
1760
1803
|
file.rewind
|
1761
1804
|
|
1762
1805
|
if link_block_data.fetch(LinkKeys::EXEC, false)
|
1763
|
-
@run_state.files =
|
1806
|
+
@run_state.files = StreamsOut.new
|
1764
1807
|
execute_command_with_streams([cmd]) do |_stdin, stdout, stderr, _thread|
|
1765
1808
|
line = stdout || stderr
|
1766
1809
|
output_lines.push(line) if line
|
@@ -1831,7 +1874,6 @@ module MarkdownExec
|
|
1831
1874
|
document_filename: File.basename(@delegate_object[:filename]),
|
1832
1875
|
document_filespec: @delegate_object[:filename],
|
1833
1876
|
home: Dir.pwd,
|
1834
|
-
# rest: '',
|
1835
1877
|
started_at: Time.now.utc.strftime(@delegate_object[:execute_command_title_time_format])
|
1836
1878
|
}
|
1837
1879
|
end
|
@@ -1886,43 +1928,6 @@ module MarkdownExec
|
|
1886
1928
|
end
|
1887
1929
|
end
|
1888
1930
|
|
1889
|
-
# private
|
1890
|
-
|
1891
|
-
# def read_block_name(line)
|
1892
|
-
# bm = extract_named_captures_from_option(line, @delegate_object[:block_name_match])
|
1893
|
-
# name = bm[:title]
|
1894
|
-
|
1895
|
-
# if @delegate_object[:block_name_nick_match].present? && line =~ Regexp.new(@delegate_object[:block_name_nick_match])
|
1896
|
-
# name = $~[0]
|
1897
|
-
# else
|
1898
|
-
# name = bm && bm[1] ? bm[:title] : name
|
1899
|
-
# end
|
1900
|
-
# name
|
1901
|
-
# end
|
1902
|
-
|
1903
|
-
# # Loads auto link block.
|
1904
|
-
# def load_auto_link_block(all_blocks, link_state, mdoc, block_source:)
|
1905
|
-
# block_name = @delegate_object[:document_load_link_block_name]
|
1906
|
-
# return unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
|
1907
|
-
|
1908
|
-
# block = HashDelegator.block_find(all_blocks, :oname, block_name)
|
1909
|
-
# return unless block
|
1910
|
-
|
1911
|
-
# if block.fetch(:shell, '') != BlockType::LINK
|
1912
|
-
# HashDelegator.error_handler('must be Link block type', { abort: true })
|
1913
|
-
|
1914
|
-
# else
|
1915
|
-
# # debounce_reset
|
1916
|
-
# push_link_history_and_trigger_load(
|
1917
|
-
# link_block_body: block.fetch(:body, ''),
|
1918
|
-
# mdoc: mdoc,
|
1919
|
-
# selected: block,
|
1920
|
-
# link_state: link_state,
|
1921
|
-
# block_source: block_source
|
1922
|
-
# )
|
1923
|
-
# end
|
1924
|
-
# end
|
1925
|
-
|
1926
1931
|
# Handle expression with wildcard characters
|
1927
1932
|
def load_filespec_wildcard_expansion(expr, auto_load_single: false)
|
1928
1933
|
files = find_files(expr)
|
@@ -1933,7 +1938,11 @@ module MarkdownExec
|
|
1933
1938
|
else
|
1934
1939
|
## user selects from existing files or other
|
1935
1940
|
#
|
1936
|
-
case (name = prompt_select_code_filename(
|
1941
|
+
case (name = prompt_select_code_filename(
|
1942
|
+
[@delegate_object[:prompt_filespec_back]] + files,
|
1943
|
+
string: @delegate_object[:prompt_select_code_file],
|
1944
|
+
color_sym: :prompt_color_after_script_execution
|
1945
|
+
))
|
1937
1946
|
when @delegate_object[:prompt_filespec_back]
|
1938
1947
|
# do nothing
|
1939
1948
|
else
|
@@ -1958,7 +1967,6 @@ module MarkdownExec
|
|
1958
1967
|
# recreate menu with new options
|
1959
1968
|
#
|
1960
1969
|
all_blocks, mdoc = mdoc_and_blocks_from_nested_files if load_auto_opts_block(all_blocks)
|
1961
|
-
# load_auto_link_block(all_blocks, link_state, mdoc, block_source: {})
|
1962
1970
|
|
1963
1971
|
menu_blocks = mdoc.fcbs_per_options(@delegate_object)
|
1964
1972
|
add_menu_chrome_blocks!(menu_blocks: menu_blocks, link_state: link_state)
|
@@ -2077,7 +2085,7 @@ module MarkdownExec
|
|
2077
2085
|
@fout.fout formatted_string
|
2078
2086
|
end
|
2079
2087
|
|
2080
|
-
def
|
2088
|
+
def fout_execution_report
|
2081
2089
|
@fout.fout fetch_color(data_sym: :execution_report_preview_head,
|
2082
2090
|
color_sym: :execution_report_preview_frame_color)
|
2083
2091
|
[
|
@@ -2101,16 +2109,16 @@ module MarkdownExec
|
|
2101
2109
|
def output_execution_summary
|
2102
2110
|
return unless @delegate_object[:output_execution_summary]
|
2103
2111
|
|
2104
|
-
fout_section 'summary', {
|
2112
|
+
@fout.fout_section 'summary', {
|
2105
2113
|
execute_aborted_at: @run_state.aborted_at,
|
2106
2114
|
execute_completed_at: @run_state.completed_at,
|
2107
2115
|
execute_error: @run_state.error,
|
2108
2116
|
execute_error_message: @run_state.error_message,
|
2109
|
-
execute_files: @run_state.files,
|
2110
2117
|
execute_options: @run_state.options,
|
2111
2118
|
execute_started_at: @run_state.started_at,
|
2119
|
+
saved_filespec: @run_state.saved_filespec,
|
2112
2120
|
script_block_name: @run_state.script_block_name,
|
2113
|
-
|
2121
|
+
streamed_lines: @run_state.files.streams
|
2114
2122
|
}
|
2115
2123
|
end
|
2116
2124
|
|
@@ -2123,6 +2131,11 @@ module MarkdownExec
|
|
2123
2131
|
), level: level
|
2124
2132
|
end
|
2125
2133
|
|
2134
|
+
def pause_user_exit
|
2135
|
+
@delegate_object[:pause_after_script_execution] &&
|
2136
|
+
prompt_select_continue == MenuState::EXIT
|
2137
|
+
end
|
2138
|
+
|
2126
2139
|
def pop_add_current_code_to_head_and_trigger_load(link_state, block_names, code_lines,
|
2127
2140
|
dependencies, selected, next_block_name: nil)
|
2128
2141
|
pop = @link_history.pop # updatable
|
@@ -2175,7 +2188,7 @@ module MarkdownExec
|
|
2175
2188
|
def post_execution_process
|
2176
2189
|
do_save_execution_output
|
2177
2190
|
output_execution_summary
|
2178
|
-
|
2191
|
+
fout_execution_report if @delegate_object[:output_execution_report]
|
2179
2192
|
end
|
2180
2193
|
|
2181
2194
|
# Prepare the blocks menu by adding labels and other necessary details.
|
@@ -2349,10 +2362,9 @@ module MarkdownExec
|
|
2349
2362
|
|
2350
2363
|
# public
|
2351
2364
|
|
2352
|
-
def prompt_select_code_filename(filenames)
|
2365
|
+
def prompt_select_code_filename(filenames, string: @delegate_object[:prompt_select_code_file], color_sym: :prompt_color_after_script_execution)
|
2353
2366
|
@prompt.select(
|
2354
|
-
string_send_color(
|
2355
|
-
:prompt_color_after_script_execution),
|
2367
|
+
string_send_color(string, color_sym),
|
2356
2368
|
filter: true,
|
2357
2369
|
quiet: true
|
2358
2370
|
) do |menu|
|
@@ -2493,7 +2505,7 @@ module MarkdownExec
|
|
2493
2505
|
end
|
2494
2506
|
|
2495
2507
|
# Registers console attributes by modifying the options hash.
|
2496
|
-
# This method handles terminal resizing and adjusts the console dimensions
|
2508
|
+
# This method handles terminal resizing and adjusts the console dimensions
|
2497
2509
|
# and pagination settings based on the current terminal size.
|
2498
2510
|
#
|
2499
2511
|
# @param opts [Hash] a hash containing various options for the console settings.
|
@@ -2510,19 +2522,15 @@ module MarkdownExec
|
|
2510
2522
|
# register_console_attributes(opts)
|
2511
2523
|
# # opts will be updated with the current console dimensions and pagination settings.
|
2512
2524
|
def register_console_attributes(opts)
|
2513
|
-
|
2514
|
-
|
2515
|
-
|
2516
|
-
end
|
2525
|
+
if (resized = @delegate_object[:menu_resize_terminal])
|
2526
|
+
resize_terminal
|
2527
|
+
end
|
2517
2528
|
|
2518
|
-
|
2519
|
-
opts[:console_height], opts[:console_width] = opts[:console_winsize] = IO.console.winsize
|
2520
|
-
end
|
2529
|
+
opts[:console_height], opts[:console_width] = opts[:console_winsize] = IO.console.winsize if resized || !opts[:console_width]
|
2521
2530
|
|
2522
|
-
|
2523
|
-
|
2524
|
-
|
2525
|
-
end
|
2531
|
+
opts[:per_page] = opts[:select_page_height] = [opts[:console_height] - 3, 4].max unless opts[:select_page_height]&.positive?
|
2532
|
+
rescue StandardError
|
2533
|
+
HashDelegator.error_handler('register_console_attributes', { abort: true })
|
2526
2534
|
end
|
2527
2535
|
|
2528
2536
|
# Check if the delegate object responds to a given method.
|
@@ -2584,8 +2592,11 @@ module MarkdownExec
|
|
2584
2592
|
## user selects from existing files or other
|
2585
2593
|
# input into path with wildcard for easy entry
|
2586
2594
|
#
|
2587
|
-
name = prompt_select_code_filename(
|
2588
|
-
|
2595
|
+
case (name = prompt_select_code_filename(
|
2596
|
+
[@delegate_object[:prompt_filespec_back], @delegate_object[:prompt_filespec_other]] + files,
|
2597
|
+
string: @delegate_object[:prompt_select_code_file],
|
2598
|
+
color_sym: :prompt_color_after_script_execution
|
2599
|
+
))
|
2589
2600
|
when @delegate_object[:prompt_filespec_back]
|
2590
2601
|
# do nothing
|
2591
2602
|
when @delegate_object[:prompt_filespec_other]
|
@@ -2712,9 +2723,13 @@ module MarkdownExec
|
|
2712
2723
|
dname = oname = title = fcb_title_groups.fetch(:name, '')
|
2713
2724
|
end
|
2714
2725
|
|
2726
|
+
# disable fcb for data blocks
|
2727
|
+
disabled = fcb_title_groups.fetch(:shell, '') == 'yaml' ? '' : nil
|
2728
|
+
|
2715
2729
|
MarkdownExec::FCB.new(
|
2716
2730
|
body: [],
|
2717
2731
|
call: rest.match(Regexp.new(@delegate_object[:block_calls_scan]))&.to_a&.first,
|
2732
|
+
disabled: disabled,
|
2718
2733
|
dname: dname,
|
2719
2734
|
headings: headings,
|
2720
2735
|
indent: fcb_title_groups.fetch(:indent, ''),
|
@@ -2848,12 +2863,12 @@ module MarkdownExec
|
|
2848
2863
|
|
2849
2864
|
time_now = Time.now.utc
|
2850
2865
|
@run_state.saved_script_filename =
|
2851
|
-
SavedAsset.
|
2852
|
-
|
2853
|
-
|
2854
|
-
|
2855
|
-
|
2856
|
-
|
2866
|
+
SavedAsset.new(blockname: selected.pub_name,
|
2867
|
+
exts: '.sh',
|
2868
|
+
filename: @delegate_object[:filename],
|
2869
|
+
prefix: @delegate_object[:saved_script_filename_prefix],
|
2870
|
+
saved_asset_format: @delegate_object[:saved_asset_format],
|
2871
|
+
time: time_now).generate_name
|
2857
2872
|
@run_state.saved_filespec =
|
2858
2873
|
File.join(@delegate_object[:saved_script_folder],
|
2859
2874
|
@run_state.saved_script_filename)
|
@@ -2942,21 +2957,6 @@ module MarkdownExec
|
|
2942
2957
|
|
2943
2958
|
def self.next_link_state(*args, **kwargs, &block)
|
2944
2959
|
super
|
2945
|
-
# result = super
|
2946
|
-
|
2947
|
-
# @logger ||= StdOutErrLogger.new
|
2948
|
-
# @logger.unknown(
|
2949
|
-
# HashDelegator.clean_hash_recursively(
|
2950
|
-
# { "HashDelegator.next_link_state":
|
2951
|
-
# { 'args': args,
|
2952
|
-
# 'at': Time.now.strftime('%FT%TZ'),
|
2953
|
-
# 'for': /[^\/]+:\d+/.match(caller.first)[0],
|
2954
|
-
# 'kwargs': kwargs,
|
2955
|
-
# 'return': result } }
|
2956
|
-
# )
|
2957
|
-
# )
|
2958
|
-
|
2959
|
-
# result
|
2960
2960
|
end
|
2961
2961
|
end
|
2962
2962
|
end
|
@@ -3468,25 +3468,27 @@ module MarkdownExec
|
|
3468
3468
|
@hd.instance_variable_set(:@run_state, mock('run_state'))
|
3469
3469
|
end
|
3470
3470
|
|
3471
|
-
def
|
3472
|
-
result = HashDelegator.
|
3473
|
-
|
3471
|
+
def test_format_execution_stream_with_valid_key
|
3472
|
+
result = HashDelegator.format_execution_stream(
|
3473
|
+
{ stdout: %w[output1 output2] },
|
3474
|
+
ExecutionStreams::STD_OUT
|
3475
|
+
)
|
3474
3476
|
|
3475
|
-
assert_equal
|
3477
|
+
assert_equal "output1\noutput2", result
|
3476
3478
|
end
|
3477
3479
|
|
3478
|
-
def
|
3480
|
+
def test_format_execution_stream_with_empty_key
|
3479
3481
|
@hd.instance_variable_get(:@run_state).stubs(:files).returns({})
|
3480
3482
|
|
3481
|
-
result = HashDelegator.
|
3483
|
+
result = HashDelegator.format_execution_stream(nil, ExecutionStreams::STD_ERR)
|
3482
3484
|
|
3483
3485
|
assert_equal '', result
|
3484
3486
|
end
|
3485
3487
|
|
3486
|
-
def
|
3488
|
+
def test_format_execution_stream_with_nil_files
|
3487
3489
|
@hd.instance_variable_get(:@run_state).stubs(:files).returns(nil)
|
3488
3490
|
|
3489
|
-
result = HashDelegator.
|
3491
|
+
result = HashDelegator.format_execution_stream(nil, :stdin)
|
3490
3492
|
|
3491
3493
|
assert_equal '', result
|
3492
3494
|
end
|
@@ -3601,19 +3603,19 @@ module MarkdownExec
|
|
3601
3603
|
|
3602
3604
|
def test_handle_stream
|
3603
3605
|
stream = StringIO.new("line 1\nline 2\n")
|
3604
|
-
file_type =
|
3606
|
+
file_type = ExecutionStreams::STD_OUT
|
3605
3607
|
|
3606
3608
|
Thread.new { @hd.handle_stream(stream: stream, file_type: file_type) }
|
3607
3609
|
|
3608
3610
|
@hd.wait_for_stream_processing
|
3609
3611
|
|
3610
3612
|
assert_equal ['line 1', 'line 2'],
|
3611
|
-
@hd.instance_variable_get(:@run_state).files[
|
3613
|
+
@hd.instance_variable_get(:@run_state).files[ExecutionStreams::STD_OUT]
|
3612
3614
|
end
|
3613
3615
|
|
3614
3616
|
def test_handle_stream_with_io_error
|
3615
3617
|
stream = StringIO.new("line 1\nline 2\n")
|
3616
|
-
file_type =
|
3618
|
+
file_type = ExecutionStreams::STD_OUT
|
3617
3619
|
stream.stubs(:each_line).raises(IOError)
|
3618
3620
|
|
3619
3621
|
Thread.new { @hd.handle_stream(stream: stream, file_type: file_type) }
|
@@ -3621,7 +3623,7 @@ module MarkdownExec
|
|
3621
3623
|
@hd.wait_for_stream_processing
|
3622
3624
|
|
3623
3625
|
assert_equal [],
|
3624
|
-
@hd.instance_variable_get(:@run_state).files[
|
3626
|
+
@hd.instance_variable_get(:@run_state).files[ExecutionStreams::STD_OUT]
|
3625
3627
|
end
|
3626
3628
|
end
|
3627
3629
|
|
data/lib/mdoc.rb
CHANGED
@@ -53,6 +53,17 @@ module MarkdownExec
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
# Collects and formats the shell command output to redirect script block code to a file or a variable.
|
57
|
+
#
|
58
|
+
# @param [Hash] fcb A hash containing information about the script block's stdout and body.
|
59
|
+
# @option fcb [Hash] :stdout A hash specifying the stdout details.
|
60
|
+
# @option stdout [Boolean] :type Indicates whether to export to a variable (true) or to write to a file (false).
|
61
|
+
# @option stdout [String] :name The name of the variable or file to which the body will be output.
|
62
|
+
# @option fcb [Array<String>] :body An array of strings representing the lines of the script block's body.
|
63
|
+
#
|
64
|
+
# @return [String] A string containing the formatted shell command to output the script block's body.
|
65
|
+
# If stdout[:type] is true, the command will export the body to a shell variable.
|
66
|
+
# If stdout[:type] is false, the command will write the body to a file.
|
56
67
|
def collect_block_code_stdout(fcb)
|
57
68
|
stdout = fcb[:stdout]
|
58
69
|
body = fcb[:body].join("\n")
|
data/lib/menu.src.yml
CHANGED
@@ -64,6 +64,7 @@
|
|
64
64
|
:procname: val_as_str
|
65
65
|
|
66
66
|
- :default: ">(?<full>(?<type>\\$)?(?<name>[A-Za-z_\\-\\.\\w]+))"
|
67
|
+
:description: Match to place block body into a file or a variable
|
67
68
|
:env_var: MDE_BLOCK_STDOUT_SCAN
|
68
69
|
:opt_name: block_stdout_scan
|
69
70
|
:procname: val_as_str
|
@@ -106,12 +107,6 @@
|
|
106
107
|
:opt_name: display_level_xbase_prefix
|
107
108
|
:procname: val_as_str
|
108
109
|
|
109
|
-
# - :default: "(document_link)"
|
110
|
-
# :description: Name of Link block to load with the document
|
111
|
-
# :env_var: MDE_DOCUMENT_LOAD_LINK_BLOCK_NAME
|
112
|
-
# :opt_name: document_load_link_block_name
|
113
|
-
# :procname: val_as_str
|
114
|
-
|
115
110
|
- :default: "(document_options)"
|
116
111
|
:description: Name of Opts block to load with the document
|
117
112
|
:env_var: MDE_DOCUMENT_LOAD_OPTS_BLOCK_NAME
|
@@ -132,6 +127,13 @@
|
|
132
127
|
:opt_name: menu_for_saved_lines
|
133
128
|
:procname: val_as_bool
|
134
129
|
|
130
|
+
- :arg_name: BOOL
|
131
|
+
:default: true
|
132
|
+
:description: Add menu options for history
|
133
|
+
:env_var: MDE_menu_for_history
|
134
|
+
:opt_name: menu_for_history
|
135
|
+
:procname: val_as_bool
|
136
|
+
|
135
137
|
- :arg_name: BOOL
|
136
138
|
:default: false
|
137
139
|
:description: Dump @delegate_object
|
@@ -648,8 +650,8 @@
|
|
648
650
|
:opt_name: menu_note_format
|
649
651
|
:procname: val_as_str
|
650
652
|
|
651
|
-
##
|
652
|
-
- :default: "^(?<line>(?!/
|
653
|
+
## lines that start with "/" are comments (hidden), not notes (visible)
|
654
|
+
- :default: "^(?<line>(?!/)(?<indent>[ \t]*)(?<text>.*?)(?<trailing>[ \t]*))?$"
|
653
655
|
:description: Pattern for notes in block selection menu
|
654
656
|
:env_var: MDE_MENU_NOTE_MATCH
|
655
657
|
:opt_name: menu_note_match
|
@@ -676,6 +678,13 @@
|
|
676
678
|
:opt_name: menu_option_exit_name
|
677
679
|
:procname: val_as_str
|
678
680
|
|
681
|
+
- :default:
|
682
|
+
:line: "* History"
|
683
|
+
:description: Text for History option
|
684
|
+
:env_var: MDE_MENU_OPTION_HISTORY_NAME
|
685
|
+
:opt_name: menu_option_history_name
|
686
|
+
:procname: val_as_str
|
687
|
+
|
679
688
|
- :default:
|
680
689
|
:line: "* Load"
|
681
690
|
:description: Text for Load option
|
@@ -868,6 +877,13 @@
|
|
868
877
|
:opt_name: output_execution_label_value_color
|
869
878
|
:procname: val_as_str
|
870
879
|
|
880
|
+
- :arg_name: BOOL
|
881
|
+
:default: true
|
882
|
+
:description: Output execution report at end of execution
|
883
|
+
:env_var: MDE_OUTPUT_EXECUTION_REPORT
|
884
|
+
:opt_name: output_execution_report
|
885
|
+
:procname: val_as_bool
|
886
|
+
|
871
887
|
- :arg_name: BOOL
|
872
888
|
:default: false
|
873
889
|
:description: Output saved script filename at end of execution
|
@@ -990,6 +1006,12 @@
|
|
990
1006
|
:opt_name: prompt_select_code_file
|
991
1007
|
:procname: val_as_str
|
992
1008
|
|
1009
|
+
- :default: "\nView file:"
|
1010
|
+
:description: Prompt to select a saved asset
|
1011
|
+
:env_var: MDE_PROMPT_SELECT_HISTORY_FILE
|
1012
|
+
:opt_name: prompt_select_history_file
|
1013
|
+
:procname: val_as_str
|
1014
|
+
|
993
1015
|
- :default: "\nChoose a file:"
|
994
1016
|
:description: Prompt to select a markdown document
|
995
1017
|
:env_var: MDE_PROMPT_SELECT_MD
|
@@ -1036,6 +1058,18 @@
|
|
1036
1058
|
:opt_name: runtime_exception_error_level
|
1037
1059
|
:procname: val_as_int
|
1038
1060
|
|
1061
|
+
- :default: '%{prefix}%{join}%{time}%{join}%{filename}%{join}%{mark}%{join}%{blockname}%{join}%{exts}'
|
1062
|
+
:description: saved_asset_format
|
1063
|
+
:env_var: MDE_SAVED_ASSET_FORMAT
|
1064
|
+
:opt_name: saved_asset_format
|
1065
|
+
:procname: val_as_str
|
1066
|
+
|
1067
|
+
- :default: "^(?<prefix>.+)(?<join>_)(?<time>[0-9\\-]+)\\g'join'(?<filename>.+)\\g'join'(?<mark>~)\\g'join'(?<blockname>.+)\\g'join'(?<exts>\\..+)$"
|
1068
|
+
:description: saved_asset_match
|
1069
|
+
:env_var: MDE_SAVED_ASSET_MATCH
|
1070
|
+
:opt_name: saved_asset_match
|
1071
|
+
:procname: val_as_str
|
1072
|
+
|
1039
1073
|
- :arg_name: BOOL
|
1040
1074
|
:default: false
|
1041
1075
|
:description: Whether to save an executed script
|
data/lib/menu.yml
CHANGED
@@ -53,6 +53,7 @@
|
|
53
53
|
:opt_name: block_stdin_scan
|
54
54
|
:procname: val_as_str
|
55
55
|
- :default: ">(?<full>(?<type>\\$)?(?<name>[A-Za-z_\\-\\.\\w]+))"
|
56
|
+
:description: Match to place block body into a file or a variable
|
56
57
|
:env_var: MDE_BLOCK_STDOUT_SCAN
|
57
58
|
:opt_name: block_stdout_scan
|
58
59
|
:procname: val_as_str
|
@@ -105,6 +106,12 @@
|
|
105
106
|
:env_var: MDE_MENU_FOR_SAVED_LINES
|
106
107
|
:opt_name: menu_for_saved_lines
|
107
108
|
:procname: val_as_bool
|
109
|
+
- :arg_name: BOOL
|
110
|
+
:default: true
|
111
|
+
:description: Add menu options for history
|
112
|
+
:env_var: MDE_menu_for_history
|
113
|
+
:opt_name: menu_for_history
|
114
|
+
:procname: val_as_bool
|
108
115
|
- :arg_name: BOOL
|
109
116
|
:default: false
|
110
117
|
:description: Dump @delegate_object
|
@@ -541,7 +548,7 @@
|
|
541
548
|
:env_var: MDE_MENU_NOTE_FORMAT
|
542
549
|
:opt_name: menu_note_format
|
543
550
|
:procname: val_as_str
|
544
|
-
- :default: "^(?<line>(?!/
|
551
|
+
- :default: "^(?<line>(?!/)(?<indent>[ \t]*)(?<text>.*?)(?<trailing>[ \t]*))?$"
|
545
552
|
:description: Pattern for notes in block selection menu
|
546
553
|
:env_var: MDE_MENU_NOTE_MATCH
|
547
554
|
:opt_name: menu_note_match
|
@@ -564,6 +571,12 @@
|
|
564
571
|
:env_var: MDE_MENU_OPTION_EXIT_NAME
|
565
572
|
:opt_name: menu_option_exit_name
|
566
573
|
:procname: val_as_str
|
574
|
+
- :default:
|
575
|
+
:line: "* History"
|
576
|
+
:description: Text for History option
|
577
|
+
:env_var: MDE_MENU_OPTION_HISTORY_NAME
|
578
|
+
:opt_name: menu_option_history_name
|
579
|
+
:procname: val_as_str
|
567
580
|
- :default:
|
568
581
|
:line: "* Load"
|
569
582
|
:description: Text for Load option
|
@@ -726,6 +739,12 @@
|
|
726
739
|
:env_var: MDE_OUTPUT_EXECUTION_LABEL_VALUE_COLOR
|
727
740
|
:opt_name: output_execution_label_value_color
|
728
741
|
:procname: val_as_str
|
742
|
+
- :arg_name: BOOL
|
743
|
+
:default: true
|
744
|
+
:description: Output execution report at end of execution
|
745
|
+
:env_var: MDE_OUTPUT_EXECUTION_REPORT
|
746
|
+
:opt_name: output_execution_report
|
747
|
+
:procname: val_as_bool
|
729
748
|
- :arg_name: BOOL
|
730
749
|
:default: false
|
731
750
|
:description: Output saved script filename at end of execution
|
@@ -841,6 +860,13 @@
|
|
841
860
|
:procname: val_as_str
|
842
861
|
- :default: |2-
|
843
862
|
|
863
|
+
View file:
|
864
|
+
:description: Prompt to select a saved asset
|
865
|
+
:env_var: MDE_PROMPT_SELECT_HISTORY_FILE
|
866
|
+
:opt_name: prompt_select_history_file
|
867
|
+
:procname: val_as_str
|
868
|
+
- :default: |2-
|
869
|
+
|
844
870
|
Choose a file:
|
845
871
|
:description: Prompt to select a markdown document
|
846
872
|
:env_var: MDE_PROMPT_SELECT_MD
|
@@ -882,6 +908,16 @@
|
|
882
908
|
:env_var: MDE_RUNTIME_EXCEPTION_ERROR_LEVEL
|
883
909
|
:opt_name: runtime_exception_error_level
|
884
910
|
:procname: val_as_int
|
911
|
+
- :default: "%{prefix}%{join}%{time}%{join}%{filename}%{join}%{mark}%{join}%{blockname}%{join}%{exts}"
|
912
|
+
:description: saved_asset_format
|
913
|
+
:env_var: MDE_SAVED_ASSET_FORMAT
|
914
|
+
:opt_name: saved_asset_format
|
915
|
+
:procname: val_as_str
|
916
|
+
- :default: "^(?<prefix>.+)(?<join>_)(?<time>[0-9\\-]+)\\g'join'(?<filename>.+)\\g'join'(?<mark>~)\\g'join'(?<blockname>.+)\\g'join'(?<exts>\\..+)$"
|
917
|
+
:description: saved_asset_match
|
918
|
+
:env_var: MDE_SAVED_ASSET_MATCH
|
919
|
+
:opt_name: saved_asset_match
|
920
|
+
:procname: val_as_str
|
885
921
|
- :arg_name: BOOL
|
886
922
|
:default: false
|
887
923
|
:description: Whether to save an executed script
|
data/lib/saved_assets.rb
CHANGED
@@ -12,23 +12,57 @@ module MarkdownExec
|
|
12
12
|
# method derives a name for stdout redirection.
|
13
13
|
#
|
14
14
|
class SavedAsset
|
15
|
-
FNR11 = %r{[
|
15
|
+
FNR11 = %r{[^!#%\+\-0-9=@A-Z_a-z]}.freeze # characters than can be used in a file name without quotes or escaping
|
16
|
+
# except '.', ',', '~' reserved for tokenization
|
16
17
|
# / !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
17
18
|
FNR12 = '_'
|
18
19
|
DEFAULT_FTIME = '%F-%H-%M-%S'
|
20
|
+
FILE_BLOCK_SEP = ','
|
21
|
+
JOIN_STR = '_'
|
22
|
+
MARK_STR = '~'
|
19
23
|
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
# @param filename [String] the name of the file
|
25
|
+
# @param prefix [String] the prefix to use
|
26
|
+
# @param time [Time] the time object for formatting
|
27
|
+
# @param blockname [String] the block name to include
|
28
|
+
# @param ftime [String] the time format (default: DEFAULT_FTIME)
|
29
|
+
# @param pattern [Regexp] the pattern to search (default: FNR11)
|
30
|
+
# @param replace [String] the string to replace the pattern (default: FNR12)
|
31
|
+
# @param exts [String] the extension to append (default: '.sh')
|
32
|
+
def initialize(
|
33
|
+
saved_asset_format:, filename: nil, prefix: nil, time: nil, blockname: nil,
|
34
|
+
ftime: DEFAULT_FTIME, pattern: FNR11, replace: FNR12, exts: nil,
|
35
|
+
mark: nil, join_str: nil
|
36
|
+
)
|
37
|
+
@filename = filename ? filename.gsub(pattern, replace) : '*' # [String] the name of the file
|
38
|
+
@prefix = prefix || '*' # [String] the prefix to use
|
39
|
+
@time = time ? time.strftime(ftime) : '*' # [Time] the time object for formatting
|
40
|
+
@blockname = blockname ? blockname.gsub(pattern, replace) : '*' # [String] the block name to include
|
41
|
+
# @ftime = ftime # [String] the time format (default: DEFAULT_FTIME)
|
42
|
+
# @pattern = pattern # [Regexp] the pattern to search (default: FNR11)
|
43
|
+
# @replace = replace # [String] the string to replace the pattern (default: FNR12)
|
44
|
+
@exts = exts || '.*' # [String] the extension to append (default: '.sh')
|
45
|
+
@mark = mark || MARK_STR
|
46
|
+
@join_str = join_str || JOIN_STR
|
47
|
+
@saved_asset_format = saved_asset_format
|
25
48
|
end
|
26
49
|
|
27
|
-
# Generates a formatted
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
50
|
+
# Generates a formatted name based on the provided parameters.
|
51
|
+
#
|
52
|
+
# @return [String] the generated formatted name
|
53
|
+
def generate_name
|
54
|
+
format(
|
55
|
+
@saved_asset_format,
|
56
|
+
{
|
57
|
+
blockname: @blockname,
|
58
|
+
exts: @exts,
|
59
|
+
filename: @filename,
|
60
|
+
join: @join_str,
|
61
|
+
mark: @mark,
|
62
|
+
prefix: @prefix,
|
63
|
+
time: @time
|
64
|
+
}
|
65
|
+
)
|
32
66
|
end
|
33
67
|
end
|
34
68
|
end
|
@@ -61,4 +95,76 @@ class SavedAssetTest < Minitest::Test
|
|
61
95
|
filename: filename, prefix: prefix, time: time, blockname: blockname
|
62
96
|
)
|
63
97
|
end
|
98
|
+
|
99
|
+
def test_wildcard_name_with_all_parameters
|
100
|
+
filename = 'sample.txt'
|
101
|
+
prefix = 'test'
|
102
|
+
time = Time.new(2023, 1, 1, 12, 0, 0)
|
103
|
+
blockname = 'block/1:2'
|
104
|
+
expected_wildcard = 'test_2023-01-01-12-00-00_sample_txt_,_block_1_2.sh'
|
105
|
+
|
106
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
|
107
|
+
filename: filename, prefix: prefix, time: time, blockname: blockname
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_wildcard_name_with_missing_time
|
112
|
+
filename = 'sample.txt'
|
113
|
+
prefix = 'test'
|
114
|
+
time = nil
|
115
|
+
blockname = 'block/1:2'
|
116
|
+
expected_wildcard = 'test_*_sample_txt_,_block_1_2.sh'
|
117
|
+
|
118
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
|
119
|
+
filename: filename, prefix: prefix, time: time, blockname: blockname
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_wildcard_name_with_missing_filename
|
124
|
+
filename = nil
|
125
|
+
prefix = 'test'
|
126
|
+
time = Time.new(2023, 1, 1, 12, 0, 0)
|
127
|
+
blockname = 'block/1:2'
|
128
|
+
expected_wildcard = 'test_2023-01-01-12-00-00_*_,_block_1_2.sh'
|
129
|
+
|
130
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
|
131
|
+
filename: filename, prefix: prefix, time: time, blockname: blockname
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_wildcard_name_with_missing_prefix
|
136
|
+
filename = 'sample.txt'
|
137
|
+
prefix = nil
|
138
|
+
time = Time.new(2023, 1, 1, 12, 0, 0)
|
139
|
+
blockname = 'block/1:2'
|
140
|
+
expected_wildcard = '*_2023-01-01-12-00-00_sample_txt_,_block_1_2.sh'
|
141
|
+
|
142
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
|
143
|
+
filename: filename, prefix: prefix, time: time, blockname: blockname
|
144
|
+
)
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_wildcard_name_with_missing_blockname
|
148
|
+
filename = 'sample.txt'
|
149
|
+
prefix = 'test'
|
150
|
+
time = Time.new(2023, 1, 1, 12, 0, 0)
|
151
|
+
blockname = nil
|
152
|
+
expected_wildcard = 'test_2023-01-01-12-00-00_sample_txt_,_*.sh'
|
153
|
+
|
154
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
|
155
|
+
filename: filename, prefix: prefix, time: time, blockname: blockname
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_wildcard_name_with_all_missing
|
160
|
+
filename = nil
|
161
|
+
prefix = nil
|
162
|
+
time = nil
|
163
|
+
blockname = nil
|
164
|
+
expected_wildcard = '*_*_*_,_*.sh'
|
165
|
+
|
166
|
+
assert_equal expected_wildcard, MarkdownExec::SavedAsset.wildcard_name(
|
167
|
+
filename: filename, prefix: prefix, time: time, blockname: blockname
|
168
|
+
)
|
169
|
+
end
|
64
170
|
end
|
data/lib/streams_out.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# encoding=utf-8
|
5
|
+
|
6
|
+
class StreamsOut
|
7
|
+
attr_accessor :streams
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@streams = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def append_stream_line(stream, line)
|
14
|
+
@streams << { stream: stream, line: line, timestamp: Time.now }
|
15
|
+
end
|
16
|
+
|
17
|
+
def write_execution_output_to_file(filespec)
|
18
|
+
FileUtils.mkdir_p File.dirname(filespec)
|
19
|
+
|
20
|
+
output = @streams.map do |entry|
|
21
|
+
case entry[:stream]
|
22
|
+
when ExecutionStreams::STD_OUT
|
23
|
+
entry[:line]
|
24
|
+
# "OUT: #{entry[:line]}"
|
25
|
+
when ExecutionStreams::STD_ERR
|
26
|
+
entry[:line]
|
27
|
+
# "ERR: #{entry[:line]}"
|
28
|
+
when ExecutionStreams::STD_IN
|
29
|
+
entry[:line]
|
30
|
+
# " IN: #{entry[:line]}"
|
31
|
+
end
|
32
|
+
end.join("\n")
|
33
|
+
|
34
|
+
File.write(filespec, output)
|
35
|
+
end
|
36
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: markdown_exec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fareed Stevenson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: clipboard
|
@@ -115,6 +115,7 @@ files:
|
|
115
115
|
- bin/tab_completion.sh.erb
|
116
116
|
- examples/block_names.md
|
117
117
|
- examples/colors.md
|
118
|
+
- examples/data-files.md
|
118
119
|
- examples/document_options.md
|
119
120
|
- examples/duplicate_block.md
|
120
121
|
- examples/import0.md
|
@@ -135,10 +136,12 @@ files:
|
|
135
136
|
- examples/load_code.md
|
136
137
|
- examples/nickname.md
|
137
138
|
- examples/opts.md
|
139
|
+
- examples/opts_output_execution.md
|
138
140
|
- examples/pass-through.md
|
139
141
|
- examples/pause-after-execution.md
|
140
142
|
- examples/plant.md
|
141
143
|
- examples/port.md
|
144
|
+
- examples/save.md
|
142
145
|
- examples/search.md
|
143
146
|
- examples/vars.md
|
144
147
|
- examples/wrap.md
|
@@ -179,6 +182,7 @@ files:
|
|
179
182
|
- lib/saved_files_matcher.rb
|
180
183
|
- lib/shared.rb
|
181
184
|
- lib/std_out_err_logger.rb
|
185
|
+
- lib/streams_out.rb
|
182
186
|
- lib/string_util.rb
|
183
187
|
- lib/tap.rb
|
184
188
|
homepage: https://rubygems.org/gems/markdown_exec
|