markdown_exec 2.0.8.3 → 2.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 +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
|