markdown_exec 0.2.4 → 0.2.5
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 +35 -1
- data/Gemfile.lock +1 -1
- data/README.md +103 -15
- data/lib/markdown_exec/version.rb +2 -2
- data/lib/markdown_exec.rb +243 -140
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95d097cfcf93e09ba3bf487989923d4be03dd9fde0521854ea0660850b157d01
|
4
|
+
data.tar.gz: 22bc0e8bc8cd35d0d1dd52b6275c1609fb4cb95d69bd125064f0ca16f2f931f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 591c09a221c0f5a34f8523d99d8e416bb022219fee38a7a05e3541600b03132e5ae3cc6aee02048eda2170a408d9e86090dedadff7c16f1f79ea98469826c27a
|
7
|
+
data.tar.gz: 74a76b6a6b10b165f8e79e59d25db78bcba173d730fd1a696e73c2012794bcfedd7c1b648cabe6b15d4d0a70995e5303b02c58d0b16c35a03ffbfea0b4efc5f4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,39 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [ToDo]
|
4
|
+
|
5
|
+
- pipe stdin to script
|
6
|
+
- yes/no/write/clipboard/record/edit/history
|
7
|
+
- present timestamp, result of last exec for each command
|
8
|
+
- user settings
|
9
|
+
- hidden w , w/o () in names
|
10
|
+
- fix regexp in pathnames
|
11
|
+
- tab completion from md file
|
12
|
+
- read file once to allow for tempdoc stream
|
13
|
+
- include md or blocks file
|
14
|
+
|
15
|
+
- tree display
|
16
|
+
|
17
|
+
- mde options in md file or included file
|
18
|
+
|
19
|
+
- include blocks from local md file
|
20
|
+
|
21
|
+
- chmod a+x logged script
|
22
|
+
|
23
|
+
- add shebang to saved script
|
24
|
+
|
25
|
+
## [0.2.5] - 2022-04
|
26
|
+
|
27
|
+
### Added
|
28
|
+
|
29
|
+
- Command `--list-default-env` to show default configuration as environment variables.
|
30
|
+
- Command `--list-default-yaml` to show default configuration as YAML.
|
31
|
+
- Option to exit program when selecting files or blocks.
|
32
|
+
|
33
|
+
### Changed
|
34
|
+
|
35
|
+
- Composition of menu to facilitate reports.
|
36
|
+
- List default values in menu help.
|
3
37
|
|
4
38
|
## [0.2.4] - 2022-04-01
|
5
39
|
|
@@ -11,7 +45,7 @@
|
|
11
45
|
|
12
46
|
| YAML Name | Environment Variable | Option Name | Default | Purpose |
|
13
47
|
| :--- | :--- | :--- | :--- | :--- |
|
14
|
-
| list_count | MDE_LIST_COUNT | `--
|
48
|
+
| list_count | MDE_LIST_COUNT | `--list-count` | `16` | Max. items to return in list |
|
15
49
|
| logged_stdout_filename_prefix | MDE_LOGGED_STDOUT_FILENAME_PREFIX | | `mde` | Name prefix for stdout files |
|
16
50
|
| save_execution_output | MDE_SAVE_EXECUTION_OUTPUT | `--save-execution-output` | False | Save standard output of the executed script |
|
17
51
|
| saved_script_filename_prefix | MDE_SAVED_SCRIPT_FILENAME_PREFIX | | `mde` | Name prefix for saved scripts |
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,30 +1,35 @@
|
|
1
1
|
# MarkdownExec
|
2
2
|
|
3
|
-
Interactively select and execute fenced code blocks in markdown files. Build complex scripts by naming and requiring blocks.
|
3
|
+
Interactively select and execute fenced code blocks in markdown files. Build complex scripts by naming and requiring blocks. Log resulting scripts and output. Re-run scripts.
|
4
4
|
|
5
|
-
* Code blocks may be named.
|
5
|
+
* Code blocks may be named. Named blocks can be required by other blocks.
|
6
6
|
|
7
|
-
*
|
7
|
+
* The user-selected code block, and all required blocks, are arranged into a script in the order they appear in the markdown file. The script can be presented for approval prior to execution.
|
8
8
|
|
9
|
-
*
|
9
|
+
* Executed scripts can be saved. Saved scripts can be listed, selected, and executed.
|
10
10
|
|
11
|
-
*
|
11
|
+
* Output from executed scripts can be saved.
|
12
12
|
|
13
13
|
## Screenshots
|
14
14
|
|
15
15
|
### Select a file
|
16
|
+
|
16
17
|

|
17
18
|
|
18
19
|
### Select a block
|
20
|
+
|
19
21
|

|
20
22
|
|
21
23
|
### Approve code
|
24
|
+
|
22
25
|

|
23
26
|
|
24
27
|
### Output
|
28
|
+
|
25
29
|

|
26
30
|
|
27
31
|
### Example blocks
|
32
|
+
|
28
33
|

|
29
34
|
|
30
35
|
## Installation
|
@@ -34,39 +39,111 @@ Install:
|
|
34
39
|
|
35
40
|
## Usage
|
36
41
|
|
37
|
-
###
|
42
|
+
### Help
|
43
|
+
|
44
|
+
#### `mde --help`
|
45
|
+
|
38
46
|
Displays help information.
|
39
47
|
|
40
|
-
###
|
48
|
+
### Basic
|
49
|
+
|
50
|
+
#### `mde`
|
51
|
+
|
41
52
|
Process `README.md` file in the current folder. Displays all the blocks in the file and allows you to select using [up], [down], and [return]. Press [ctrl]-c to abort selection.
|
42
53
|
|
43
|
-
|
54
|
+
#### `mde my.md` or `mde -f my.md`
|
55
|
+
|
44
56
|
Select a block to execute from `my.md`.
|
45
57
|
|
46
|
-
|
58
|
+
#### `mde .` or `mde -p .`
|
47
59
|
|
48
60
|
Select a markdown file in the current folder. Select a block to execute from that file.
|
49
61
|
|
50
|
-
###
|
62
|
+
### Report documents and blocks
|
63
|
+
|
64
|
+
#### `mde --list-blocks`
|
65
|
+
|
51
66
|
List all blocks in the all the markdown documents in the current folder.
|
52
67
|
|
53
|
-
|
68
|
+
#### `mde --list-docs`
|
69
|
+
|
54
70
|
List all markdown documents in the current folder.
|
55
71
|
|
72
|
+
### Configuration
|
73
|
+
|
74
|
+
#### `mde --list-default-env` or `mde --list-default-yaml`
|
75
|
+
|
76
|
+
List default values that can be set in configuration file, environment, and command line.
|
77
|
+
|
78
|
+
#### `mde -0`
|
79
|
+
|
80
|
+
Show current configuation values that will be applied to the current run. Does not interrupt processing.
|
81
|
+
|
82
|
+
### Save scripts
|
83
|
+
|
84
|
+
#### `mde --save-executed-script 1`
|
85
|
+
|
86
|
+
Save executed script in saved script folder.
|
87
|
+
|
88
|
+
#### `mde --list-recent-scripts`
|
89
|
+
|
90
|
+
List recent saved scripts in saved script folder.
|
91
|
+
|
92
|
+
#### `mde --select-recent-script`
|
93
|
+
|
94
|
+
Select and execute a recently saved script in saved script folder.
|
95
|
+
|
96
|
+
### Save output
|
97
|
+
|
98
|
+
#### `mde --save-execution-output 1`
|
99
|
+
|
100
|
+
Save execution output in saved output folder.
|
101
|
+
|
56
102
|
## Behavior
|
103
|
+
|
57
104
|
* If no file and no folder are specified, blocks within `./README.md` are presented.
|
58
105
|
* If a file is specified, its blocks are presented.
|
59
106
|
* If a folder is specified, its files are presented. When a file is selected, its blocks are presented.
|
60
107
|
|
61
108
|
## Configuration
|
62
|
-
While starting up, reads the YAML configuration file `.mde.yml` in the current folder if it exists.
|
63
109
|
|
64
|
-
|
110
|
+
### Environment Variables
|
111
|
+
|
112
|
+
When executed, `mde` reads the current environment.
|
113
|
+
* Configuration in current and children shells, e.g. `export MDE_SAVE_EXECUTED_SCRIPT=1`.
|
114
|
+
* Configuration for the current command, e.g. `MDE_SAVE_EXECUTED_SCRIPT=1 mde`.
|
115
|
+
|
116
|
+
### Configuration Files
|
117
|
+
|
118
|
+
* Configuration in all shells, e.g. environment variables set in your user's `~/.bashrc` or `~/.bash_profile` files.
|
119
|
+
* Configuration in the optional file `.mde.yml` in the current folder. .e.g. `save_executed_script: true`
|
120
|
+
* Configuration in a YAML file and read while parsing the inputs, e.g. `--config my_path/my_file.yml`
|
65
121
|
|
66
|
-
|
67
|
-
|
122
|
+
### Program Arguments
|
123
|
+
|
124
|
+
* Configuration in command options, e.g. `mde --save-executed-script 1`
|
125
|
+
|
126
|
+
## Representing boolean values
|
127
|
+
|
128
|
+
Boolean values expressed as strings are interpreted as:
|
129
|
+
| String | Boolean |
|
130
|
+
| :---: | :---: |
|
131
|
+
| *empty string* | False |
|
132
|
+
| `0` | False |
|
133
|
+
| `1` | True |
|
134
|
+
| *anything else* | True |
|
135
|
+
|
136
|
+
E.g. `opt1=1` will set option `opt1` to True.
|
137
|
+
|
138
|
+
Boolean options configured with environment variables:
|
139
|
+
- Set to `1` or non-empty value to save executed scripts; empty or `0` to disable saving.
|
140
|
+
e.g. `export MDE_SAVE_EXECUTED_SCRIPT=1`
|
141
|
+
e.g. `export MDE_SAVE_EXECUTED_SCRIPT=`
|
142
|
+
- Specify variable on command line.
|
143
|
+
e.g. `MDE_SAVE_EXECUTED_SCRIPT=1 mde`
|
68
144
|
|
69
145
|
# Example blocks
|
146
|
+
|
70
147
|
When prompted, select either the `awake` or `asleep` block.
|
71
148
|
|
72
149
|
``` :(day)
|
@@ -89,6 +166,17 @@ export ACTIVITY=asleep
|
|
89
166
|
echo "$TIME -> $ACTIVITY"
|
90
167
|
```
|
91
168
|
|
169
|
+
``` :missing_command
|
170
|
+
fail
|
171
|
+
```
|
172
|
+
|
173
|
+
``` :exit_value
|
174
|
+
echo "a"
|
175
|
+
echo "b"
|
176
|
+
echo "c" >>/dev/stderr
|
177
|
+
grep nx Gemfile
|
178
|
+
```
|
179
|
+
|
92
180
|
# License
|
93
181
|
|
94
182
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/markdown_exec.rb
CHANGED
@@ -14,21 +14,23 @@ require 'yaml'
|
|
14
14
|
# else true
|
15
15
|
|
16
16
|
def env_bool(name, default: false)
|
17
|
-
return default if (val = ENV[name]).nil?
|
17
|
+
return default if name.nil? || (val = ENV[name]).nil?
|
18
18
|
return false if val.empty? || val == '0'
|
19
19
|
|
20
20
|
true
|
21
21
|
end
|
22
22
|
|
23
23
|
def env_int(name, default: 0)
|
24
|
-
return default if (val = ENV[name]).nil?
|
24
|
+
return default if name.nil? || (val = ENV[name]).nil?
|
25
25
|
return default if val.empty?
|
26
26
|
|
27
27
|
val.to_i
|
28
28
|
end
|
29
29
|
|
30
30
|
def env_str(name, default: '')
|
31
|
-
ENV[name]
|
31
|
+
return default if name.nil? || (val = ENV[name]).nil?
|
32
|
+
|
33
|
+
val || default
|
32
34
|
end
|
33
35
|
|
34
36
|
$pdebug = env_bool 'MDE_DEBUG'
|
@@ -42,7 +44,12 @@ BLOCK_SIZE = 1024
|
|
42
44
|
|
43
45
|
class Object # rubocop:disable Style/Documentation
|
44
46
|
def present?
|
45
|
-
self
|
47
|
+
case self.class.to_s
|
48
|
+
when 'FalseClass', 'TrueClass'
|
49
|
+
true
|
50
|
+
else
|
51
|
+
self && (!respond_to?(:blank?) || !blank?)
|
52
|
+
end
|
46
53
|
end
|
47
54
|
end
|
48
55
|
|
@@ -94,44 +101,17 @@ module MarkdownExec
|
|
94
101
|
# options necessary to start, parse input, defaults for cli options
|
95
102
|
|
96
103
|
def base_options
|
97
|
-
|
98
|
-
#
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
logged_stdout_filename_prefix: 'mde',
|
109
|
-
output_execution_summary: env_bool('MDE_OUTPUT_EXECUTION_SUMMARY', default: false), # option
|
110
|
-
output_script: env_bool('MDE_OUTPUT_SCRIPT', default: false), # option
|
111
|
-
output_stdout: env_bool('MDE_OUTPUT_STDOUT', default: true), # option
|
112
|
-
path: env_str('MDE_PATH', default: nil), # option Folder to search for files
|
113
|
-
save_executed_script: env_bool('MDE_SAVE_EXECUTED_SCRIPT', default: false), # option
|
114
|
-
save_execution_output: env_bool('MDE_SAVE_EXECUTION_OUTPUT', default: false), # option
|
115
|
-
saved_script_filename_prefix: 'mde',
|
116
|
-
saved_script_folder: env_str('MDE_SAVED_SCRIPT_FOLDER', default: 'logs'), # option
|
117
|
-
saved_script_glob: 'mde_*.sh',
|
118
|
-
saved_stdout_folder: env_str('MDE_SAVED_STDOUT_FOLDER', default: 'logs'), # option
|
119
|
-
user_must_approve: env_bool('MDE_USER_MUST_APPROVE', default: true), # option Pause for user to approve script
|
120
|
-
|
121
|
-
# configuration options
|
122
|
-
block_name_excluded_match: env_str('MDE_BLOCK_NAME_EXCLUDED_MATCH', default: '^\(.+\)$'),
|
123
|
-
block_name_match: env_str('MDE_BLOCK_NAME_MATCH', default: ':(?<title>\S+)( |$)'),
|
124
|
-
block_required_scan: env_str('MDE_BLOCK_REQUIRED_SCAN', default: '\+\S+'),
|
125
|
-
fenced_start_and_end_match: env_str('MDE_FENCED_START_AND_END_MATCH', default: '^`{3,}'),
|
126
|
-
fenced_start_ex_match: env_str('MDE_FENCED_START_EX_MATCH', default: '^`{3,}(?<shell>[^`\s]*) *(?<name>.*)$'),
|
127
|
-
heading1_match: env_str('MDE_HEADING1_MATCH', default: '^# *(?<name>[^#]*?) *$'),
|
128
|
-
heading2_match: env_str('MDE_HEADING2_MATCH', default: '^## *(?<name>[^#]*?) *$'),
|
129
|
-
heading3_match: env_str('MDE_HEADING3_MATCH', default: '^### *(?<name>.+?) *$'),
|
130
|
-
md_filename_glob: env_str('MDE_MD_FILENAME_GLOB', default: '*.[Mm][Dd]'),
|
131
|
-
md_filename_match: env_str('MDE_MD_FILENAME_MATCH', default: '.+\\.md'),
|
132
|
-
mdheadings: true, # use headings (levels 1,2,3) in block lable
|
133
|
-
select_page_height: env_int('MDE_SELECT_PAGE_HEIGHT', default: 12)
|
134
|
-
}
|
104
|
+
menu_data
|
105
|
+
.map do |_long_name, _short_name, env_var, _arg_name, _description, opt_name, default, _proc1| # rubocop:disable Metrics/ParameterLists
|
106
|
+
next unless opt_name.present?
|
107
|
+
|
108
|
+
[opt_name, env_bool(env_var, default: value_for_hash(default))]
|
109
|
+
end.compact.to_h.merge(
|
110
|
+
{
|
111
|
+
mdheadings: true, # use headings (levels 1,2,3) in block lable
|
112
|
+
menu_with_exit: true
|
113
|
+
}
|
114
|
+
).tap_inspect format: :yaml
|
135
115
|
end
|
136
116
|
|
137
117
|
def default_options
|
@@ -248,11 +228,21 @@ module MarkdownExec
|
|
248
228
|
return
|
249
229
|
end
|
250
230
|
|
231
|
+
if @options[:list_default_yaml]
|
232
|
+
fout_list list_default_yaml
|
233
|
+
return
|
234
|
+
end
|
235
|
+
|
251
236
|
if @options[:list_docs]
|
252
237
|
fout_list files
|
253
238
|
return
|
254
239
|
end
|
255
240
|
|
241
|
+
if @options[:list_default_env]
|
242
|
+
fout_list list_default_env
|
243
|
+
return
|
244
|
+
end
|
245
|
+
|
256
246
|
if @options[:list_recent_scripts]
|
257
247
|
fout_list list_recent_scripts
|
258
248
|
return
|
@@ -376,14 +366,37 @@ module MarkdownExec
|
|
376
366
|
blocks.tap_inspect
|
377
367
|
end
|
378
368
|
|
369
|
+
def list_default_env
|
370
|
+
menu_data
|
371
|
+
.map do |_long_name, _short_name, env_var, _arg_name, description, _opt_name, default, _proc1| # rubocop:disable Metrics/ParameterLists
|
372
|
+
next unless env_var.present?
|
373
|
+
|
374
|
+
[
|
375
|
+
"#{env_var}=#{value_for_cli default}",
|
376
|
+
description.present? ? description : nil
|
377
|
+
].compact.join(' # ')
|
378
|
+
end.compact.sort
|
379
|
+
end
|
380
|
+
|
381
|
+
def list_default_yaml
|
382
|
+
menu_data
|
383
|
+
.map do |_long_name, _short_name, _env_var, _arg_name, description, opt_name, default, _proc1| # rubocop:disable Metrics/ParameterLists
|
384
|
+
next unless opt_name.present? && default.present?
|
385
|
+
|
386
|
+
[
|
387
|
+
"#{opt_name}: #{value_for_yaml default}",
|
388
|
+
description.present? ? description : nil
|
389
|
+
].compact.join(' # ')
|
390
|
+
end.compact.sort
|
391
|
+
end
|
392
|
+
|
379
393
|
def list_files_per_options(options)
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
end.tap_inspect
|
394
|
+
list_files_specified(
|
395
|
+
options[:filename]&.present? ? options[:filename] : nil,
|
396
|
+
options[:path],
|
397
|
+
'README.md',
|
398
|
+
'.'
|
399
|
+
).tap_inspect
|
387
400
|
end
|
388
401
|
|
389
402
|
def list_files_specified(specified_filename, specified_folder, default_filename, default_folder, filetree = nil)
|
@@ -462,6 +475,92 @@ module MarkdownExec
|
|
462
475
|
end.compact.tap_inspect
|
463
476
|
end
|
464
477
|
|
478
|
+
def menu_data
|
479
|
+
proc_self = ->(value) { value }
|
480
|
+
proc_to_i = ->(value) { value.to_i != 0 }
|
481
|
+
proc_true = ->(_) { true }
|
482
|
+
|
483
|
+
summary_head = [
|
484
|
+
['config', nil, nil, 'PATH', 'Read configuration file',
|
485
|
+
nil, '.', ->(value) { read_configuration_file! options, value }],
|
486
|
+
['debug', 'd', 'MDE_DEBUG', 'BOOL', 'Debug output',
|
487
|
+
nil, false, ->(value) { $pdebug = value.to_i != 0 }]
|
488
|
+
]
|
489
|
+
|
490
|
+
summary_body = [
|
491
|
+
['filename', 'f', 'MDE_FILENAME', 'RELATIVE', 'Name of document',
|
492
|
+
:filename, nil, proc_self],
|
493
|
+
['list-blocks', nil, nil, nil, 'List blocks',
|
494
|
+
:list_blocks, nil, proc_true],
|
495
|
+
['list-default-env', nil, nil, nil, 'List default configuration as environment variables',
|
496
|
+
:list_default_env, nil, proc_true],
|
497
|
+
['list-default-yaml', nil, nil, nil, 'List default configuration as YAML',
|
498
|
+
:list_default_yaml, nil, proc_true],
|
499
|
+
['list-docs', nil, nil, nil, 'List docs in current folder',
|
500
|
+
:list_docs, nil, proc_true],
|
501
|
+
['list-recent-scripts', nil, nil, nil, 'List recent saved scripts',
|
502
|
+
:list_recent_scripts, nil, proc_true],
|
503
|
+
['output-execution-summary', nil, 'MDE_OUTPUT_EXECUTION_SUMMARY', 'BOOL', 'Display summary for execution',
|
504
|
+
:output_execution_summary, false, proc_to_i],
|
505
|
+
['output-script', nil, 'MDE_OUTPUT_SCRIPT', 'BOOL', 'Display script prior to execution',
|
506
|
+
:output_script, false, proc_to_i],
|
507
|
+
['output-stdout', nil, 'MDE_OUTPUT_STDOUT', 'BOOL', 'Display standard output from execution',
|
508
|
+
:output_stdout, true, proc_to_i],
|
509
|
+
['path', 'p', 'MDE_PATH', 'PATH', 'Path to documents',
|
510
|
+
:path, nil, proc_self],
|
511
|
+
['run-last-script', nil, nil, nil, 'Run most recently saved script',
|
512
|
+
:run_last_script, nil, proc_true],
|
513
|
+
['select-recent-script', nil, nil, nil, 'Select and execute a recently saved script',
|
514
|
+
:select_recent_script, nil, proc_true],
|
515
|
+
['save-execution-output', nil, 'MDE_SAVE_EXECUTION_OUTPUT', 'BOOL', 'Save execution output',
|
516
|
+
:save_execution_output, false, proc_to_i],
|
517
|
+
['save-executed-script', nil, 'MDE_SAVE_EXECUTED_SCRIPT', 'BOOL', 'Save executed script',
|
518
|
+
:save_executed_script, false, proc_to_i],
|
519
|
+
['saved-script-folder', nil, 'MDE_SAVED_SCRIPT_FOLDER', 'SPEC', 'Saved script folder',
|
520
|
+
:saved_script_folder, 'logs', proc_self],
|
521
|
+
['saved-stdout-folder', nil, 'MDE_SAVED_STDOUT_FOLDER', 'SPEC', 'Saved stdout folder',
|
522
|
+
:saved_stdout_folder, 'logs', proc_self],
|
523
|
+
['user-must-approve', nil, 'MDE_USER_MUST_APPROVE', 'BOOL', 'Pause for user to approve script',
|
524
|
+
:user_must_approve, true, proc_to_i]
|
525
|
+
]
|
526
|
+
|
527
|
+
# rubocop:disable Style/Semicolon
|
528
|
+
summary_tail = [
|
529
|
+
[nil, '0', nil, nil, 'Show current configuration values',
|
530
|
+
nil, nil, ->(_) { options_finalize options; fout sorted_keys(options).to_yaml }],
|
531
|
+
['help', 'h', nil, nil, 'App help',
|
532
|
+
nil, nil, ->(_) { fout menu_help; exit }],
|
533
|
+
['version', 'v', nil, nil, 'App version',
|
534
|
+
nil, nil, ->(_) { fout MarkdownExec::VERSION; exit }],
|
535
|
+
['exit', 'x', nil, nil, 'Exit app',
|
536
|
+
nil, nil, ->(_) { exit }]
|
537
|
+
]
|
538
|
+
# rubocop:enable Style/Semicolon
|
539
|
+
|
540
|
+
env_vars = [
|
541
|
+
[nil, nil, 'MDE_BLOCK_NAME_EXCLUDED_MATCH', nil, 'Pattern for blocks to hide from user-selection',
|
542
|
+
:block_name_excluded_match, '^\(.+\)$', nil],
|
543
|
+
[nil, nil, 'MDE_BLOCK_NAME_MATCH', nil, '', :block_name_match, ':(?<title>\S+)( |$)', nil],
|
544
|
+
[nil, nil, 'MDE_BLOCK_REQUIRED_SCAN', nil, '', :block_required_scan, '\+\S+', nil],
|
545
|
+
[nil, nil, 'MDE_FENCED_START_AND_END_MATCH', nil, '', :fenced_start_and_end_match, '^`{3,}', nil],
|
546
|
+
[nil, nil, 'MDE_FENCED_START_EX_MATCH', nil, '', :fenced_start_ex_match,
|
547
|
+
'^`{3,}(?<shell>[^`\s]*) *(?<name>.*)$', nil],
|
548
|
+
[nil, nil, 'MDE_HEADING1_MATCH', nil, '', :heading1_match, '^# *(?<name>[^#]*?) *$', nil],
|
549
|
+
[nil, nil, 'MDE_HEADING2_MATCH', nil, '', :heading2_match, '^## *(?<name>[^#]*?) *$', nil],
|
550
|
+
[nil, nil, 'MDE_HEADING3_MATCH', nil, '', :heading3_match, '^### *(?<name>.+?) *$', nil],
|
551
|
+
[nil, nil, 'MDE_MD_FILENAME_GLOB', nil, '', :md_filename_glob, '*.[Mm][Dd]', nil],
|
552
|
+
[nil, nil, 'MDE_MD_FILENAME_MATCH', nil, '', :md_filename_match, '.+\\.md', nil],
|
553
|
+
[nil, nil, 'MDE_SELECT_PAGE_HEIGHT', nil, '', :select_page_height, 12, nil]
|
554
|
+
# [nil, nil, 'MDE_', nil, '', nil, '', nil],
|
555
|
+
]
|
556
|
+
|
557
|
+
summary_head + summary_body + summary_tail + env_vars
|
558
|
+
end
|
559
|
+
|
560
|
+
def menu_help
|
561
|
+
@option_parser.help
|
562
|
+
end
|
563
|
+
|
465
564
|
def option_exclude_blocks(opts, blocks)
|
466
565
|
block_name_excluded_match = Regexp.new opts[:block_name_excluded_match]
|
467
566
|
if opts[:hide_blocks_by_name]
|
@@ -471,6 +570,26 @@ module MarkdownExec
|
|
471
570
|
end
|
472
571
|
end
|
473
572
|
|
573
|
+
## post-parse options configuration
|
574
|
+
#
|
575
|
+
def options_finalize(rest)
|
576
|
+
## position 0: file or folder (optional)
|
577
|
+
#
|
578
|
+
if (pos = rest.fetch(0, nil))&.present?
|
579
|
+
if Dir.exist?(pos)
|
580
|
+
@options[:path] = pos
|
581
|
+
elsif File.exist?(pos)
|
582
|
+
@options[:filename] = pos
|
583
|
+
else
|
584
|
+
raise "Invalid parameter: #{pos}"
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
## position 1: block name (optional)
|
589
|
+
#
|
590
|
+
@options[:block_name] = rest.fetch(1, nil)
|
591
|
+
end
|
592
|
+
|
474
593
|
def optsmerge(call_options = {}, options_block = nil)
|
475
594
|
class_call_options = @options.merge(call_options || {})
|
476
595
|
if options_block
|
@@ -495,6 +614,14 @@ module MarkdownExec
|
|
495
614
|
}
|
496
615
|
end
|
497
616
|
|
617
|
+
def prompt_with_quit(prompt_text, items, opts = {})
|
618
|
+
exit_option = '* Exit'
|
619
|
+
sel = @prompt.select prompt_text,
|
620
|
+
items + (@options[:menu_with_exit] ? [exit_option] : []),
|
621
|
+
opts
|
622
|
+
sel == exit_option ? nil : sel
|
623
|
+
end
|
624
|
+
|
498
625
|
def read_configuration_file!(options, configuration_path)
|
499
626
|
return unless File.exist?(configuration_path)
|
500
627
|
|
@@ -526,19 +653,11 @@ module MarkdownExec
|
|
526
653
|
#
|
527
654
|
@options = base_options
|
528
655
|
|
529
|
-
##
|
530
|
-
#
|
531
|
-
options_finalize = ->(_options) {}
|
532
|
-
|
533
|
-
proc_self = ->(value) { value }
|
534
|
-
proc_to_i = ->(value) { value.to_i != 0 }
|
535
|
-
proc_true = ->(_) { true }
|
536
|
-
|
537
|
-
# read local configuration file
|
656
|
+
## read local configuration file
|
538
657
|
#
|
539
658
|
read_configuration_file! @options, ".#{MarkdownExec::APP_NAME.downcase}.yml"
|
540
659
|
|
541
|
-
option_parser = OptionParser.new do |opts|
|
660
|
+
@option_parser = option_parser = OptionParser.new do |opts|
|
542
661
|
executable_name = File.basename($PROGRAM_NAME)
|
543
662
|
opts.banner = [
|
544
663
|
"#{MarkdownExec::APP_NAME}" \
|
@@ -546,67 +665,16 @@ module MarkdownExec
|
|
546
665
|
"Usage: #{executable_name} [path] [filename] [options]"
|
547
666
|
].join("\n")
|
548
667
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
nil, ->(value) { $pdebug = value.to_i != 0 }]
|
554
|
-
]
|
555
|
-
|
556
|
-
summary_body = [
|
557
|
-
['filename', 'f', 'MDE_FILENAME', 'RELATIVE', 'Name of document',
|
558
|
-
:filename, proc_self],
|
559
|
-
['list-blocks', nil, nil, nil, 'List blocks',
|
560
|
-
:list_blocks, proc_true],
|
561
|
-
['list-docs', nil, nil, nil, 'List docs in current folder',
|
562
|
-
:list_docs, proc_true],
|
563
|
-
['list-recent-scripts', nil, nil, nil, 'List recent saved scripts',
|
564
|
-
:list_recent_scripts, proc_true],
|
565
|
-
['output-execution-summary', nil, 'MDE_OUTPUT_EXECUTION_SUMMARY', 'BOOL', 'Display summary for execution',
|
566
|
-
:output_execution_summary, proc_to_i],
|
567
|
-
['output-script', nil, 'MDE_OUTPUT_SCRIPT', 'BOOL', 'Display script',
|
568
|
-
:output_script, proc_to_i],
|
569
|
-
['output-stdout', nil, 'MDE_OUTPUT_STDOUT', 'BOOL', 'Display standard output from execution',
|
570
|
-
:output_stdout, proc_to_i],
|
571
|
-
['path', 'p', 'MDE_PATH', 'PATH', 'Path to documents',
|
572
|
-
:path, proc_self],
|
573
|
-
['run-last-script', nil, nil, nil, 'Run most recently saved script',
|
574
|
-
:run_last_script, proc_true],
|
575
|
-
['select-recent-script', nil, nil, nil, 'Select and execute a recently saved script',
|
576
|
-
:select_recent_script, proc_true],
|
577
|
-
['save-execution-output', nil, 'MDE_SAVE_EXECUTION_OUTPUT', 'BOOL', 'Save execution output',
|
578
|
-
:save_execution_output, proc_to_i],
|
579
|
-
['save-executed-script', nil, 'MDE_SAVE_EXECUTED_SCRIPT', 'BOOL', 'Save executed script',
|
580
|
-
:save_executed_script, proc_to_i],
|
581
|
-
['saved-script-folder', nil, 'MDE_SAVED_SCRIPT_FOLDER', 'SPEC', 'Saved script folder',
|
582
|
-
:saved_script_folder, proc_self],
|
583
|
-
['saved-stdout-folder', nil, 'MDE_SAVED_STDOUT_FOLDER', 'SPEC', 'Saved stdout folder',
|
584
|
-
:saved_stdout_folder, proc_self],
|
585
|
-
['user-must-approve', nil, 'MDE_USER_MUST_APPROVE', 'BOOL', 'Pause to approve execution',
|
586
|
-
:user_must_approve, proc_to_i]
|
587
|
-
]
|
588
|
-
|
589
|
-
# rubocop:disable Style/Semicolon
|
590
|
-
summary_tail = [
|
591
|
-
[nil, '0', nil, nil, 'Show configuration',
|
592
|
-
nil, ->(_) { options_finalize.call options; fout sorted_keys(options).to_yaml }],
|
593
|
-
['help', 'h', nil, nil, 'App help',
|
594
|
-
nil, ->(_) { fout option_parser.help; exit }],
|
595
|
-
['version', 'v', nil, nil, 'App version',
|
596
|
-
nil, ->(_) { fout MarkdownExec::VERSION; exit }],
|
597
|
-
['exit', 'x', nil, nil, 'Exit app',
|
598
|
-
nil, ->(_) { exit }]
|
599
|
-
]
|
600
|
-
# rubocop:enable Style/Semicolon
|
601
|
-
|
602
|
-
(summary_head + summary_body + summary_tail)
|
603
|
-
.map do |long_name, short_name, env_var, arg_name, description, opt_name, proc1| # rubocop:disable Metrics/ParameterLists
|
668
|
+
menu_data
|
669
|
+
.map do |long_name, short_name, _env_var, arg_name, description, opt_name, default, proc1| # rubocop:disable Metrics/ParameterLists
|
670
|
+
next unless long_name.present? || short_name.present?
|
671
|
+
|
604
672
|
opts.on(*[if long_name.present?
|
605
673
|
"--#{long_name}#{arg_name.present? ? " #{arg_name}" : ''}"
|
606
674
|
end,
|
607
675
|
short_name.present? ? "-#{short_name}" : nil,
|
608
676
|
[description,
|
609
|
-
|
677
|
+
default.present? ? "[#{value_for_cli default}]" : nil].compact.join(' '),
|
610
678
|
lambda { |value|
|
611
679
|
ret = proc1.call(value)
|
612
680
|
options[opt_name] = ret if opt_name
|
@@ -618,27 +686,9 @@ module MarkdownExec
|
|
618
686
|
option_parser.environment # env defaults to the basename of the program.
|
619
687
|
rest = option_parser.parse! # (into: options)
|
620
688
|
|
621
|
-
|
622
|
-
#
|
623
|
-
options_finalize.call options
|
624
|
-
|
625
|
-
## position 0: file or folder (optional)
|
626
|
-
#
|
627
|
-
if (pos = rest.fetch(0, nil))&.present?
|
628
|
-
if Dir.exist?(pos)
|
629
|
-
options[:path] = pos
|
630
|
-
elsif File.exist?(pos)
|
631
|
-
options[:filename] = pos
|
632
|
-
else
|
633
|
-
raise "Invalid parameter: #{pos}"
|
634
|
-
end
|
635
|
-
end
|
689
|
+
options_finalize rest
|
636
690
|
|
637
|
-
|
638
|
-
#
|
639
|
-
block_name = rest.fetch(1, nil)
|
640
|
-
|
641
|
-
exec_block options, block_name
|
691
|
+
exec_block options, options[:block_name]
|
642
692
|
end
|
643
693
|
|
644
694
|
def run_last_script
|
@@ -667,6 +717,12 @@ module MarkdownExec
|
|
667
717
|
dirname = File.dirname(@options[:logged_stdout_filespec])
|
668
718
|
Dir.mkdir dirname unless File.exist?(dirname)
|
669
719
|
File.write(@options[:logged_stdout_filespec], @execute_files&.fetch(0, ''))
|
720
|
+
# @options[:logged_stderr_filename] =
|
721
|
+
# "#{[@options[:logged_stdout_filename_prefix], Time.now.utc.strftime('%F-%H-%M-%S'), fne,
|
722
|
+
# @options[:block_name]].join('_')}.err.txt"
|
723
|
+
# @options[:logged_stderr_filespec] = File.join @options[:saved_stdout_folder], @options[:logged_stderr_filename]
|
724
|
+
# @logged_stderr_filespec = @options[:logged_stderr_filespec]
|
725
|
+
# File.write(@options[:logged_stderr_filespec], @execute_files&.fetch(1, ''))
|
670
726
|
end
|
671
727
|
|
672
728
|
def select_and_approve_block(call_options = {}, &options_block)
|
@@ -680,7 +736,9 @@ module MarkdownExec
|
|
680
736
|
|
681
737
|
return nil if block_labels.count.zero?
|
682
738
|
|
683
|
-
sel =
|
739
|
+
sel = prompt_with_quit pt, block_labels, per_page: opts[:select_page_height]
|
740
|
+
return nil if sel.nil?
|
741
|
+
|
684
742
|
label_block = blocks_in_file.select { |block| block[:label] == sel }.fetch(0, nil)
|
685
743
|
opts[:block_name] = @options[:block_name] = label_block[:name]
|
686
744
|
end
|
@@ -694,13 +752,15 @@ module MarkdownExec
|
|
694
752
|
if files.count == 1
|
695
753
|
files[0]
|
696
754
|
elsif files.count >= 2
|
697
|
-
|
755
|
+
prompt_with_quit opts[:prompt_select_md].to_s, files, per_page: opts[:select_page_height]
|
698
756
|
end
|
699
757
|
end
|
700
758
|
|
701
759
|
def select_recent_script
|
702
|
-
filename =
|
703
|
-
|
760
|
+
filename = prompt_with_quit @options[:prompt_select_md].to_s, list_recent_scripts,
|
761
|
+
per_page: @options[:select_page_height]
|
762
|
+
return if filename.nil?
|
763
|
+
|
704
764
|
mf = filename.match(/#{@options[:saved_script_filename_prefix]}_(?<time>[0-9\-]+)_(?<file>.+)_(?<block>.+)\.sh/)
|
705
765
|
|
706
766
|
@options[:block_name] = mf[:block]
|
@@ -728,7 +788,50 @@ module MarkdownExec
|
|
728
788
|
else
|
729
789
|
@options.merge! opts
|
730
790
|
end
|
731
|
-
@options
|
791
|
+
@options.tap_inspect format: :yaml
|
792
|
+
end
|
793
|
+
|
794
|
+
def value_for_cli(value)
|
795
|
+
case value.class.to_s
|
796
|
+
when 'String'
|
797
|
+
"'#{value}'"
|
798
|
+
when 'FalseClass', 'TrueClass'
|
799
|
+
value ? '1' : '0'
|
800
|
+
when 'Integer'
|
801
|
+
value
|
802
|
+
else
|
803
|
+
value.to_s
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
807
|
+
def value_for_hash(value, default = nil)
|
808
|
+
return default if value.nil?
|
809
|
+
|
810
|
+
case value.class.to_s
|
811
|
+
when 'String', 'Integer', 'FalseClass', 'TrueClass'
|
812
|
+
value
|
813
|
+
when value.empty?
|
814
|
+
default
|
815
|
+
else
|
816
|
+
value.to_s
|
817
|
+
end
|
818
|
+
end
|
819
|
+
|
820
|
+
def value_for_yaml(value)
|
821
|
+
return default if value.nil?
|
822
|
+
|
823
|
+
case value.class.to_s
|
824
|
+
when 'String'
|
825
|
+
"'#{value}'"
|
826
|
+
when 'Integer'
|
827
|
+
value
|
828
|
+
when 'FalseClass', 'TrueClass'
|
829
|
+
value ? true : false
|
830
|
+
when value.empty?
|
831
|
+
default
|
832
|
+
else
|
833
|
+
value.to_s
|
834
|
+
end
|
732
835
|
end
|
733
836
|
|
734
837
|
def write_command_file(opts, required_blocks)
|
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: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fareed Stevenson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-04-
|
11
|
+
date: 2022-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: open3
|
@@ -67,7 +67,8 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 0.2.0
|
69
69
|
description: Interactively select and execute fenced code blocks in markdown files.
|
70
|
-
Build complex scripts by naming and requiring blocks.
|
70
|
+
Build complex scripts by naming and requiring blocks. Log resulting scripts and
|
71
|
+
output. Re-run scripts.
|
71
72
|
email:
|
72
73
|
- fareed@phomento.com
|
73
74
|
executables:
|
@@ -127,5 +128,5 @@ requirements: []
|
|
127
128
|
rubygems_version: 3.2.32
|
128
129
|
signing_key:
|
129
130
|
specification_version: 4
|
130
|
-
summary:
|
131
|
+
summary: Interactively select and execute fenced code blocks in markdown files.
|
131
132
|
test_files: []
|