markdown_exec 0.2.4 → 1.0.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 +59 -1
- data/Gemfile.lock +1 -1
- data/README.md +117 -16
- data/assets/approve_code.png +0 -0
- data/assets/output_of_execution.png +0 -0
- data/assets/select_a_block.png +0 -0
- data/assets/select_a_file.png +0 -0
- data/bin/tab_completion.sh +23 -0
- data/fixtures/exclude2.md +3 -0
- data/lib/markdown_exec/version.rb +2 -2
- data/lib/markdown_exec.rb +329 -197
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b40d575297112f5a4bb934475b84251aeeab8f43de5dae963c8d3b1711c3edc
|
4
|
+
data.tar.gz: 9e3d3273dc3e3a0deb326fe30e3ff70b15e73f4fd9cea06c42f099f184903fad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65654b5af78419591c41e3b50e0697b503ddf429c83312311335dd1b16d0d645c98b4e0c19d6c69446c42823861ca8f384788aeb4c1b5664804e4feecc39a45a
|
7
|
+
data.tar.gz: 866360b40733e8925c173582f3c59799e241bf48f52faffa4bfb03cd4c1a11c93f5b27305344b01c4b44a1518ef1c49961c7fbfbdb713638ed8261c8d87401c0
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,63 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [ToDo]
|
4
|
+
|
5
|
+
- pipe stdin to script
|
6
|
+
- present timestamp, result of last exec for each command
|
7
|
+
- user settings
|
8
|
+
- hidden w , w/o () in names
|
9
|
+
- fix regexp in pathnames
|
10
|
+
- tab completion from md file
|
11
|
+
- read file once to allow for tempdoc stream
|
12
|
+
- include md or blocks file
|
13
|
+
|
14
|
+
- tree display
|
15
|
+
|
16
|
+
- mde options in md file or included file
|
17
|
+
|
18
|
+
- include blocks from local md file
|
19
|
+
|
20
|
+
- chmod a+x logged script
|
21
|
+
|
22
|
+
- add shebang to saved script
|
23
|
+
|
24
|
+
- yes/no/write/clipboard/record/edit/history
|
25
|
+
|
26
|
+
- list, view saved output
|
27
|
+
|
28
|
+
## [1.0.0] - 2022-04-26
|
29
|
+
|
30
|
+
### Added
|
31
|
+
|
32
|
+
- Command `--pwd` to print the gem's home folder.
|
33
|
+
- Command `--select-recent-output` to select and open a recent output log file.
|
34
|
+
e.g. `MDE_OUTPUT_VIEWER_OPTIONS="-a '/Applications/Sublime Text.app'" mde --select-recent-output`
|
35
|
+
- Command `--tab-completions` to list the application options.
|
36
|
+
- Tab completion script for Bash shell.
|
37
|
+
|
38
|
+
### Changed
|
39
|
+
|
40
|
+
- File names for saved scripts.
|
41
|
+
- Hide blocks with empty names, e.g. `:()`.
|
42
|
+
|
43
|
+
## [0.2.6] - 2022-04-07
|
44
|
+
|
45
|
+
### Changed
|
46
|
+
|
47
|
+
- Default values for command line options.
|
48
|
+
|
49
|
+
## [0.2.5] - 2022-04-03
|
50
|
+
|
51
|
+
### Added
|
52
|
+
|
53
|
+
- Command `--list-default-env` to show default configuration as environment variables.
|
54
|
+
- Command `--list-default-yaml` to show default configuration as YAML.
|
55
|
+
- Option to exit program when selecting files or blocks.
|
56
|
+
|
57
|
+
### Changed
|
58
|
+
|
59
|
+
- Composition of menu to facilitate reports.
|
60
|
+
- List default values in menu help.
|
3
61
|
|
4
62
|
## [0.2.4] - 2022-04-01
|
5
63
|
|
@@ -11,7 +69,7 @@
|
|
11
69
|
|
12
70
|
| YAML Name | Environment Variable | Option Name | Default | Purpose |
|
13
71
|
| :--- | :--- | :--- | :--- | :--- |
|
14
|
-
| list_count | MDE_LIST_COUNT | `--
|
72
|
+
| list_count | MDE_LIST_COUNT | `--list-count` | `16` | Max. items to return in list |
|
15
73
|
| logged_stdout_filename_prefix | MDE_LOGGED_STDOUT_FILENAME_PREFIX | | `mde` | Name prefix for stdout files |
|
16
74
|
| save_execution_output | MDE_SAVE_EXECUTION_OUTPUT | `--save-execution-output` | False | Save standard output of the executed script |
|
17
75
|
| 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
|
![Select a file](/assets/select_a_file.png)
|
17
18
|
|
18
19
|
### Select a block
|
20
|
+
|
19
21
|
![Select a block](/assets/select_a_block.png)
|
20
22
|
|
21
23
|
### Approve code
|
24
|
+
|
22
25
|
![Approve code](/assets/approve_code.png)
|
23
26
|
|
24
27
|
### Output
|
28
|
+
|
25
29
|
![Output of execution](/assets/output_of_execution.png)
|
26
30
|
|
27
31
|
### Example blocks
|
32
|
+
|
28
33
|
![Example blocks](/assets/example_blocks.png)
|
29
34
|
|
30
35
|
## Installation
|
@@ -34,39 +39,135 @@ 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 my.md myblock`
|
59
|
+
|
60
|
+
Execute the block named `myblock` from `my.md`.
|
61
|
+
|
62
|
+
#### `mde .` or `mde -p .`
|
47
63
|
|
48
64
|
Select a markdown file in the current folder. Select a block to execute from that file.
|
49
65
|
|
50
|
-
###
|
66
|
+
### Report documents and blocks
|
67
|
+
|
68
|
+
#### `mde --list-blocks`
|
69
|
+
|
51
70
|
List all blocks in the all the markdown documents in the current folder.
|
52
71
|
|
53
|
-
|
72
|
+
#### `mde --list-docs`
|
73
|
+
|
54
74
|
List all markdown documents in the current folder.
|
55
75
|
|
76
|
+
### Configuration
|
77
|
+
|
78
|
+
#### `mde --list-default-env` or `mde --list-default-yaml`
|
79
|
+
|
80
|
+
List default values that can be set in configuration file, environment, and command line.
|
81
|
+
|
82
|
+
#### `mde -0`
|
83
|
+
|
84
|
+
Show current configuation values that will be applied to the current run. Does not interrupt processing.
|
85
|
+
|
86
|
+
### Save scripts
|
87
|
+
|
88
|
+
#### `mde --save-executed-script 1`
|
89
|
+
|
90
|
+
Save executed script in saved script folder.
|
91
|
+
|
92
|
+
#### `mde --list-recent-scripts`
|
93
|
+
|
94
|
+
List recent saved scripts in saved script folder.
|
95
|
+
|
96
|
+
#### `mde --select-recent-script`
|
97
|
+
|
98
|
+
Select and execute a recently saved script in saved script folder.
|
99
|
+
|
100
|
+
### Save output
|
101
|
+
|
102
|
+
#### `mde --save-execution-output 1`
|
103
|
+
|
104
|
+
Save execution output in saved output folder.
|
105
|
+
|
56
106
|
## Behavior
|
107
|
+
|
57
108
|
* If no file and no folder are specified, blocks within `./README.md` are presented.
|
58
109
|
* If a file is specified, its blocks are presented.
|
59
110
|
* If a folder is specified, its files are presented. When a file is selected, its blocks are presented.
|
60
111
|
|
61
112
|
## Configuration
|
62
|
-
While starting up, reads the YAML configuration file `.mde.yml` in the current folder if it exists.
|
63
113
|
|
64
|
-
|
114
|
+
### Environment Variables
|
115
|
+
|
116
|
+
When executed, `mde` reads the current environment.
|
117
|
+
* Configuration in current and children shells, e.g. `export MDE_SAVE_EXECUTED_SCRIPT=1`.
|
118
|
+
* Configuration for the current command, e.g. `MDE_SAVE_EXECUTED_SCRIPT=1 mde`.
|
119
|
+
|
120
|
+
### Configuration Files
|
121
|
+
|
122
|
+
* Configuration in all shells, e.g. environment variables set in your user's `~/.bashrc` or `~/.bash_profile` files.
|
123
|
+
* Configuration in the optional file `.mde.yml` in the current folder. .e.g. `save_executed_script: true`
|
124
|
+
* Configuration in a YAML file and read while parsing the inputs, e.g. `--config my_path/my_file.yml`
|
125
|
+
|
126
|
+
### Program Arguments
|
127
|
+
|
128
|
+
* Configuration in command options, e.g. `mde --save-executed-script 1`
|
129
|
+
|
130
|
+
## Representing boolean values
|
131
|
+
|
132
|
+
Boolean values expressed as strings are interpreted as:
|
133
|
+
| String | Boolean |
|
134
|
+
| :---: | :---: |
|
135
|
+
| *empty string* | False |
|
136
|
+
| `0` | False |
|
137
|
+
| `1` | True |
|
138
|
+
| *anything else* | True |
|
139
|
+
|
140
|
+
E.g. `opt1=1` will set option `opt1` to True.
|
141
|
+
|
142
|
+
Boolean options configured with environment variables:
|
143
|
+
- Set to `1` or non-empty value to save executed scripts; empty or `0` to disable saving.
|
144
|
+
e.g. `export MDE_SAVE_EXECUTED_SCRIPT=1`
|
145
|
+
e.g. `export MDE_SAVE_EXECUTED_SCRIPT=`
|
146
|
+
- Specify variable on command line.
|
147
|
+
e.g. `MDE_SAVE_EXECUTED_SCRIPT=1 mde`
|
148
|
+
|
149
|
+
## Tab Completion
|
150
|
+
|
151
|
+
### Install tab completion
|
152
|
+
|
153
|
+
Append a command to load the completion script to your shell configuration file:
|
154
|
+
|
155
|
+
```bash :()
|
156
|
+
echo "source $(mde --pwd)/bin/tab_completion.sh" >> ~/.bash_profile
|
157
|
+
```
|
158
|
+
|
159
|
+
### Example Completions
|
160
|
+
|
161
|
+
Type tab at end of any of the following commands to see the options.
|
162
|
+
- `mde `
|
163
|
+
- `mde -`
|
164
|
+
- `mde --`
|
165
|
+
- `mde --o`
|
166
|
+
- `mde --filename my.md -`
|
167
|
+
- `mde --filename my.md --`
|
65
168
|
|
66
|
-
|
67
|
-
* `folder: documents` sets the folder to search for default or specified files.
|
169
|
+
## Example Blocks
|
68
170
|
|
69
|
-
# Example blocks
|
70
171
|
When prompted, select either the `awake` or `asleep` block.
|
71
172
|
|
72
173
|
``` :(day)
|
data/assets/approve_code.png
CHANGED
Binary file
|
Binary file
|
data/assets/select_a_block.png
CHANGED
Binary file
|
data/assets/select_a_file.png
CHANGED
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
__filedirs()
|
4
|
+
{
|
5
|
+
local IFS=$'\n'
|
6
|
+
COMPREPLY=( $(compgen -o plusdirs -f -- "${cur}") )
|
7
|
+
}
|
8
|
+
|
9
|
+
_mde() {
|
10
|
+
local cur prev opts
|
11
|
+
cur="${COMP_WORDS[COMP_CWORD]}"
|
12
|
+
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
13
|
+
opts="$(mde --tab-completions)"
|
14
|
+
|
15
|
+
if [[ ${cur} == -* ]] ; then
|
16
|
+
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
17
|
+
return 0
|
18
|
+
fi
|
19
|
+
|
20
|
+
__filedirs
|
21
|
+
}
|
22
|
+
|
23
|
+
complete -o filenames -F _mde mde
|
data/fixtures/exclude2.md
CHANGED
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
|
|
@@ -60,16 +67,13 @@ public
|
|
60
67
|
def tap_inspect(format: nil, name: 'return')
|
61
68
|
return self unless $pdebug
|
62
69
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
else
|
71
|
-
:inspect
|
72
|
-
end
|
70
|
+
cvt = {
|
71
|
+
json: :to_json,
|
72
|
+
string: :to_s,
|
73
|
+
yaml: :to_yaml,
|
74
|
+
else: :inspect
|
75
|
+
}
|
76
|
+
fn = cvt.fetch(format, cvt[:else])
|
73
77
|
|
74
78
|
puts "-> #{caller[0].scan(/in `?(\S+)'$/)[0][0]}()" \
|
75
79
|
" #{name}: #{method(fn).call}"
|
@@ -94,44 +98,18 @@ module MarkdownExec
|
|
94
98
|
# options necessary to start, parse input, defaults for cli options
|
95
99
|
|
96
100
|
def base_options
|
97
|
-
|
98
|
-
#
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
}
|
101
|
+
menu_data
|
102
|
+
.map do |_long_name, _short_name, env_var, _arg_name, _description, opt_name, default, proc1| # rubocop:disable Metrics/ParameterLists
|
103
|
+
next unless opt_name.present?
|
104
|
+
|
105
|
+
value = env_str(env_var, default: value_for_hash(default))
|
106
|
+
[opt_name, proc1 ? proc1.call(value) : value]
|
107
|
+
end.compact.to_h.merge(
|
108
|
+
{
|
109
|
+
mdheadings: true, # use headings (levels 1,2,3) in block lable
|
110
|
+
menu_with_exit: true
|
111
|
+
}
|
112
|
+
).tap_inspect format: :yaml
|
135
113
|
end
|
136
114
|
|
137
115
|
def default_options
|
@@ -143,6 +121,7 @@ module MarkdownExec
|
|
143
121
|
prompt_approve_block: 'Process?',
|
144
122
|
prompt_select_block: 'Choose a block:',
|
145
123
|
prompt_select_md: 'Choose a file:',
|
124
|
+
prompt_select_output: 'Choose a file:',
|
146
125
|
saved_script_filename: nil, # calculated
|
147
126
|
struct: true # allow get_block_summary()
|
148
127
|
}
|
@@ -164,8 +143,10 @@ module MarkdownExec
|
|
164
143
|
selected = get_block_by_name blocks_in_file, opts[:block_name]
|
165
144
|
|
166
145
|
if opts[:ir_approve]
|
167
|
-
write_command_file
|
146
|
+
write_command_file opts, required_blocks
|
168
147
|
command_execute opts, required_blocks.flatten.join("\n")
|
148
|
+
save_execution_output
|
149
|
+
output_execution_summary
|
169
150
|
end
|
170
151
|
|
171
152
|
selected[:name]
|
@@ -241,31 +222,30 @@ module MarkdownExec
|
|
241
222
|
# document and block reports
|
242
223
|
#
|
243
224
|
files = list_files_per_options(options)
|
244
|
-
if @options[:list_blocks]
|
245
|
-
fout_list (files.map do |file|
|
246
|
-
make_block_labels(filename: file, struct: true)
|
247
|
-
end).flatten(1)
|
248
|
-
return
|
249
|
-
end
|
250
225
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
226
|
+
simple_commands = {
|
227
|
+
doc_glob: -> { fout options[:md_filename_glob] },
|
228
|
+
list_blocks: lambda do
|
229
|
+
fout_list (files.map do |file|
|
230
|
+
make_block_labels(filename: file, struct: true)
|
231
|
+
end).flatten(1)
|
232
|
+
end,
|
233
|
+
list_default_yaml: -> { fout_list list_default_yaml },
|
234
|
+
list_docs: -> { fout_list files },
|
235
|
+
list_default_env: -> { fout_list list_default_env },
|
236
|
+
list_recent_output: -> { fout_list list_recent_output },
|
237
|
+
list_recent_scripts: -> { fout_list list_recent_scripts },
|
238
|
+
pwd: -> { fout File.expand_path('..', __dir__) },
|
239
|
+
run_last_script: -> { run_last_script },
|
240
|
+
select_recent_output: -> { select_recent_output },
|
241
|
+
select_recent_script: -> { select_recent_script },
|
242
|
+
tab_completions: -> { fout tab_completions }
|
243
|
+
}
|
244
|
+
simple_commands.each_key do |key|
|
245
|
+
if @options[key]
|
246
|
+
simple_commands[key].call
|
247
|
+
return # rubocop:disable Lint/NonLocalExitFromIterator
|
248
|
+
end
|
269
249
|
end
|
270
250
|
|
271
251
|
# process
|
@@ -276,8 +256,6 @@ module MarkdownExec
|
|
276
256
|
struct: true
|
277
257
|
)
|
278
258
|
fout "saved_filespec: #{@execute_script_filespec}" if @options[:output_saved_script_filename]
|
279
|
-
save_execution_output
|
280
|
-
output_execution_summary
|
281
259
|
end
|
282
260
|
|
283
261
|
# standard output; not for debug
|
@@ -322,6 +300,11 @@ module MarkdownExec
|
|
322
300
|
exit 1
|
323
301
|
end
|
324
302
|
|
303
|
+
unless File.exist? opts[:filename]
|
304
|
+
fout 'Document is missing.'
|
305
|
+
exit 1
|
306
|
+
end
|
307
|
+
|
325
308
|
fenced_start_and_end_match = Regexp.new opts[:fenced_start_and_end_match]
|
326
309
|
fenced_start_ex = Regexp.new opts[:fenced_start_ex_match]
|
327
310
|
block_title = ''
|
@@ -376,14 +359,37 @@ module MarkdownExec
|
|
376
359
|
blocks.tap_inspect
|
377
360
|
end
|
378
361
|
|
362
|
+
def list_default_env
|
363
|
+
menu_data
|
364
|
+
.map do |_long_name, _short_name, env_var, _arg_name, description, _opt_name, default, _proc1| # rubocop:disable Metrics/ParameterLists
|
365
|
+
next unless env_var.present?
|
366
|
+
|
367
|
+
[
|
368
|
+
"#{env_var}=#{value_for_cli default}",
|
369
|
+
description.present? ? description : nil
|
370
|
+
].compact.join(' # ')
|
371
|
+
end.compact.sort
|
372
|
+
end
|
373
|
+
|
374
|
+
def list_default_yaml
|
375
|
+
menu_data
|
376
|
+
.map do |_long_name, _short_name, _env_var, _arg_name, description, opt_name, default, _proc1| # rubocop:disable Metrics/ParameterLists
|
377
|
+
next unless opt_name.present? && default.present?
|
378
|
+
|
379
|
+
[
|
380
|
+
"#{opt_name}: #{value_for_yaml default}",
|
381
|
+
description.present? ? description : nil
|
382
|
+
].compact.join(' # ')
|
383
|
+
end.compact.sort
|
384
|
+
end
|
385
|
+
|
379
386
|
def list_files_per_options(options)
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
end.tap_inspect
|
387
|
+
list_files_specified(
|
388
|
+
options[:filename]&.present? ? options[:filename] : nil,
|
389
|
+
options[:path],
|
390
|
+
'README.md',
|
391
|
+
'.'
|
392
|
+
).tap_inspect
|
387
393
|
end
|
388
394
|
|
389
395
|
def list_files_specified(specified_filename, specified_folder, default_filename, default_folder, filetree = nil)
|
@@ -438,9 +444,28 @@ module MarkdownExec
|
|
438
444
|
.tap_inspect
|
439
445
|
end
|
440
446
|
|
447
|
+
def most_recent(arr)
|
448
|
+
return unless arr
|
449
|
+
return if arr.count < 1
|
450
|
+
|
451
|
+
arr.max.tap_inspect
|
452
|
+
end
|
453
|
+
|
454
|
+
def most_recent_list(arr)
|
455
|
+
return unless arr
|
456
|
+
return if (ac = arr.count) < 1
|
457
|
+
|
458
|
+
arr.sort[-[ac, options[:list_count]].min..].reverse.tap_inspect
|
459
|
+
end
|
460
|
+
|
461
|
+
def list_recent_output
|
462
|
+
most_recent_list(Dir.glob(File.join(@options[:saved_stdout_folder],
|
463
|
+
@options[:saved_stdout_glob]))).tap_inspect
|
464
|
+
end
|
465
|
+
|
441
466
|
def list_recent_scripts
|
442
|
-
Dir.glob(File.join(@options[:saved_script_folder],
|
443
|
-
|
467
|
+
most_recent_list(Dir.glob(File.join(@options[:saved_script_folder],
|
468
|
+
@options[:saved_script_glob]))).tap_inspect
|
444
469
|
end
|
445
470
|
|
446
471
|
def make_block_label(block, call_options = {})
|
@@ -462,6 +487,89 @@ module MarkdownExec
|
|
462
487
|
end.compact.tap_inspect
|
463
488
|
end
|
464
489
|
|
490
|
+
def menu_data
|
491
|
+
val_as_bool = ->(value) { value.class.to_s == 'String' ? (value.chomp != '0') : value }
|
492
|
+
val_as_int = ->(value) { value.to_i }
|
493
|
+
val_as_str = ->(value) { value.to_s }
|
494
|
+
|
495
|
+
summary_head = [
|
496
|
+
['config', nil, nil, 'PATH', 'Read configuration file', nil, '.', lambda { |value|
|
497
|
+
read_configuration_file! options, value
|
498
|
+
}],
|
499
|
+
['debug', 'd', 'MDE_DEBUG', 'BOOL', 'Debug output', nil, false, ->(value) { $pdebug = value.to_i != 0 }]
|
500
|
+
]
|
501
|
+
|
502
|
+
# rubocop:disable Layout/LineLength
|
503
|
+
summary_body = [
|
504
|
+
['block-name', 'f', 'MDE_BLOCK_NAME', 'RELATIVE', 'Name of block', :block_name, nil, val_as_str],
|
505
|
+
['filename', 'f', 'MDE_FILENAME', 'RELATIVE', 'Name of document', :filename, nil, val_as_str],
|
506
|
+
['list-blocks', nil, nil, nil, 'List blocks', :list_blocks, false, val_as_bool],
|
507
|
+
['list-count', nil, 'MDE_LIST_COUNT', 'NUM', 'Max. items to return in list', :list_count, 16, val_as_int],
|
508
|
+
['list-default-env', nil, nil, nil, 'List default configuration as environment variables', :list_default_env, false, val_as_bool],
|
509
|
+
['list-default-yaml', nil, nil, nil, 'List default configuration as YAML', :list_default_yaml, false, val_as_bool],
|
510
|
+
['list-docs', nil, nil, nil, 'List docs in current folder', :list_docs, false, val_as_bool],
|
511
|
+
['list-recent-output', nil, nil, nil, 'List recent saved output', :list_recent_output, false, val_as_bool],
|
512
|
+
['list-recent-scripts', nil, nil, nil, 'List recent saved scripts', :list_recent_scripts, false, val_as_bool],
|
513
|
+
['logged-stdout-filename-prefix', nil, 'MDE_LOGGED_STDOUT_FILENAME_PREFIX', 'NAME', 'Name prefix for stdout files', :logged_stdout_filename_prefix, 'mde', val_as_str],
|
514
|
+
['output-execution-summary', nil, 'MDE_OUTPUT_EXECUTION_SUMMARY', 'BOOL', 'Display summary for execution', :output_execution_summary, false, val_as_bool],
|
515
|
+
['output-script', nil, 'MDE_OUTPUT_SCRIPT', 'BOOL', 'Display script prior to execution', :output_script, false, val_as_bool],
|
516
|
+
['output-stdout', nil, 'MDE_OUTPUT_STDOUT', 'BOOL', 'Display standard output from execution', :output_stdout, true, val_as_bool],
|
517
|
+
['path', 'p', 'MDE_PATH', 'PATH', 'Path to documents', :path, nil, val_as_str],
|
518
|
+
['pwd', nil, nil, nil, 'Gem home folder', :pwd, false, val_as_bool],
|
519
|
+
['run-last-script', nil, nil, nil, 'Run most recently saved script', :run_last_script, false, val_as_bool],
|
520
|
+
['save-executed-script', nil, 'MDE_SAVE_EXECUTED_SCRIPT', 'BOOL', 'Save executed script', :save_executed_script, false, val_as_bool],
|
521
|
+
['save-execution-output', nil, 'MDE_SAVE_EXECUTION_OUTPUT', 'BOOL', 'Save standard output of the executed script', :save_execution_output, false, val_as_bool],
|
522
|
+
['saved-script-filename-prefix', nil, 'MDE_SAVED_SCRIPT_FILENAME_PREFIX', 'NAME', 'Name prefix for saved scripts', :saved_script_filename_prefix, 'mde', val_as_str],
|
523
|
+
['saved-script-folder', nil, 'MDE_SAVED_SCRIPT_FOLDER', 'SPEC', 'Saved script folder', :saved_script_folder, 'logs', val_as_str],
|
524
|
+
['saved-script-glob', nil, 'MDE_SAVED_SCRIPT_GLOB', 'SPEC', 'Glob matching saved scripts', :saved_script_glob, 'mde_*.sh', val_as_str],
|
525
|
+
['saved-stdout-folder', nil, 'MDE_SAVED_STDOUT_FOLDER', 'SPEC', 'Saved stdout folder', :saved_stdout_folder, 'logs', val_as_str],
|
526
|
+
['saved-stdout-glob', nil, 'MDE_SAVED_STDOUT_GLOB', 'SPEC', 'Glob matching saved outputs', :saved_stdout_glob, 'mde_*.out.txt', val_as_str],
|
527
|
+
['select-recent-output', nil, nil, nil, 'Select and execute a recently saved output', :select_recent_output, false, val_as_bool],
|
528
|
+
['select-recent-script', nil, nil, nil, 'Select and execute a recently saved script', :select_recent_script, false, val_as_bool],
|
529
|
+
['tab-completions', nil, nil, nil, 'List tab completions', :tab_completions, false, val_as_bool],
|
530
|
+
['user-must-approve', nil, 'MDE_USER_MUST_APPROVE', 'BOOL', 'Pause for user to approve script', :user_must_approve, true, val_as_bool]
|
531
|
+
]
|
532
|
+
# rubocop:enable Layout/LineLength
|
533
|
+
|
534
|
+
# rubocop:disable Style/Semicolon
|
535
|
+
summary_tail = [
|
536
|
+
[nil, '0', nil, nil, 'Show current configuration values',
|
537
|
+
nil, nil, ->(_) { options_finalize options; fout sorted_keys(options).to_yaml }],
|
538
|
+
['help', 'h', nil, nil, 'App help',
|
539
|
+
nil, nil, ->(_) { fout menu_help; exit }],
|
540
|
+
['version', 'v', nil, nil, "Print the gem's version",
|
541
|
+
nil, nil, ->(_) { fout MarkdownExec::VERSION; exit }],
|
542
|
+
['exit', 'x', nil, nil, 'Exit app',
|
543
|
+
nil, nil, ->(_) { exit }]
|
544
|
+
]
|
545
|
+
# rubocop:enable Style/Semicolon
|
546
|
+
|
547
|
+
env_vars = [
|
548
|
+
[nil, nil, 'MDE_BLOCK_NAME_EXCLUDED_MATCH', nil, 'Pattern for blocks to hide from user-selection',
|
549
|
+
:block_name_excluded_match, '^\(.*\)$', val_as_str],
|
550
|
+
[nil, nil, 'MDE_BLOCK_NAME_MATCH', nil, '', :block_name_match, ':(?<title>\S+)( |$)', val_as_str],
|
551
|
+
[nil, nil, 'MDE_BLOCK_REQUIRED_SCAN', nil, '', :block_required_scan, '\+\S+', val_as_str],
|
552
|
+
[nil, nil, 'MDE_FENCED_START_AND_END_MATCH', nil, '', :fenced_start_and_end_match, '^`{3,}', val_as_str],
|
553
|
+
[nil, nil, 'MDE_FENCED_START_EX_MATCH', nil, '', :fenced_start_ex_match,
|
554
|
+
'^`{3,}(?<shell>[^`\s]*) *(?<name>.*)$', val_as_str],
|
555
|
+
[nil, nil, 'MDE_HEADING1_MATCH', nil, '', :heading1_match, '^# *(?<name>[^#]*?) *$', val_as_str],
|
556
|
+
[nil, nil, 'MDE_HEADING2_MATCH', nil, '', :heading2_match, '^## *(?<name>[^#]*?) *$', val_as_str],
|
557
|
+
[nil, nil, 'MDE_HEADING3_MATCH', nil, '', :heading3_match, '^### *(?<name>.+?) *$', val_as_str],
|
558
|
+
[nil, nil, 'MDE_MD_FILENAME_GLOB', nil, '', :md_filename_glob, '*.[Mm][Dd]', val_as_str],
|
559
|
+
[nil, nil, 'MDE_MD_FILENAME_MATCH', nil, '', :md_filename_match, '.+\\.md', val_as_str],
|
560
|
+
[nil, nil, 'MDE_OUTPUT_VIEWER_OPTIONS', nil, 'Options for viewing saved output file', :output_viewer_options,
|
561
|
+
'', val_as_str],
|
562
|
+
[nil, nil, 'MDE_SELECT_PAGE_HEIGHT', nil, '', :select_page_height, 12, val_as_int]
|
563
|
+
# [nil, nil, 'MDE_', nil, '', nil, '', nil],
|
564
|
+
]
|
565
|
+
|
566
|
+
summary_head + summary_body + summary_tail + env_vars
|
567
|
+
end
|
568
|
+
|
569
|
+
def menu_help
|
570
|
+
@option_parser.help
|
571
|
+
end
|
572
|
+
|
465
573
|
def option_exclude_blocks(opts, blocks)
|
466
574
|
block_name_excluded_match = Regexp.new opts[:block_name_excluded_match]
|
467
575
|
if opts[:hide_blocks_by_name]
|
@@ -471,6 +579,27 @@ module MarkdownExec
|
|
471
579
|
end
|
472
580
|
end
|
473
581
|
|
582
|
+
## post-parse options configuration
|
583
|
+
#
|
584
|
+
def options_finalize(rest)
|
585
|
+
## position 0: file or folder (optional)
|
586
|
+
#
|
587
|
+
if (pos = rest.fetch(0, nil))&.present?
|
588
|
+
if Dir.exist?(pos)
|
589
|
+
@options[:path] = pos
|
590
|
+
elsif File.exist?(pos)
|
591
|
+
@options[:filename] = pos
|
592
|
+
else
|
593
|
+
raise "Invalid parameter: #{pos}"
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
## position 1: block name (optional)
|
598
|
+
#
|
599
|
+
block_name = rest.fetch(1, nil)
|
600
|
+
@options[:block_name] = block_name if block_name.present?
|
601
|
+
end
|
602
|
+
|
474
603
|
def optsmerge(call_options = {}, options_block = nil)
|
475
604
|
class_call_options = @options.merge(call_options || {})
|
476
605
|
if options_block
|
@@ -495,6 +624,14 @@ module MarkdownExec
|
|
495
624
|
}
|
496
625
|
end
|
497
626
|
|
627
|
+
def prompt_with_quit(prompt_text, items, opts = {})
|
628
|
+
exit_option = '* Exit'
|
629
|
+
sel = @prompt.select prompt_text,
|
630
|
+
items + (@options[:menu_with_exit] ? [exit_option] : []),
|
631
|
+
opts
|
632
|
+
sel == exit_option ? nil : sel
|
633
|
+
end
|
634
|
+
|
498
635
|
def read_configuration_file!(options, configuration_path)
|
499
636
|
return unless File.exist?(configuration_path)
|
500
637
|
|
@@ -526,87 +663,28 @@ module MarkdownExec
|
|
526
663
|
#
|
527
664
|
@options = base_options
|
528
665
|
|
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
|
666
|
+
## read local configuration file
|
538
667
|
#
|
539
668
|
read_configuration_file! @options, ".#{MarkdownExec::APP_NAME.downcase}.yml"
|
540
669
|
|
541
|
-
option_parser = OptionParser.new do |opts|
|
670
|
+
@option_parser = option_parser = OptionParser.new do |opts|
|
542
671
|
executable_name = File.basename($PROGRAM_NAME)
|
543
672
|
opts.banner = [
|
544
673
|
"#{MarkdownExec::APP_NAME}" \
|
545
674
|
" - #{MarkdownExec::APP_DESC} (#{MarkdownExec::VERSION})",
|
546
|
-
"Usage: #{executable_name} [path
|
675
|
+
"Usage: #{executable_name} [(path | filename [block_name])] [options]"
|
547
676
|
].join("\n")
|
548
677
|
|
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
|
678
|
+
menu_data
|
679
|
+
.map do |long_name, short_name, _env_var, arg_name, description, opt_name, default, proc1| # rubocop:disable Metrics/ParameterLists
|
680
|
+
next unless long_name.present? || short_name.present?
|
681
|
+
|
604
682
|
opts.on(*[if long_name.present?
|
605
683
|
"--#{long_name}#{arg_name.present? ? " #{arg_name}" : ''}"
|
606
684
|
end,
|
607
685
|
short_name.present? ? "-#{short_name}" : nil,
|
608
686
|
[description,
|
609
|
-
|
687
|
+
default.present? ? "[#{value_for_cli default}]" : nil].compact.join(' '),
|
610
688
|
lambda { |value|
|
611
689
|
ret = proc1.call(value)
|
612
690
|
options[opt_name] = ret if opt_name
|
@@ -618,47 +696,44 @@ module MarkdownExec
|
|
618
696
|
option_parser.environment # env defaults to the basename of the program.
|
619
697
|
rest = option_parser.parse! # (into: options)
|
620
698
|
|
621
|
-
|
622
|
-
#
|
623
|
-
options_finalize.call options
|
699
|
+
options_finalize rest
|
624
700
|
|
625
|
-
|
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
|
701
|
+
exec_block options, options[:block_name]
|
702
|
+
end
|
636
703
|
|
637
|
-
|
638
|
-
|
639
|
-
|
704
|
+
FNR11 = '/'
|
705
|
+
FNR12 = ',;'
|
706
|
+
|
707
|
+
def saved_name_make(opts)
|
708
|
+
fne = opts[:filename].gsub(FNR11, FNR12)
|
709
|
+
"#{[opts[:saved_script_filename_prefix], Time.now.utc.strftime('%F-%H-%M-%S'), fne,
|
710
|
+
',', opts[:block_name]].join('_')}.sh"
|
711
|
+
end
|
712
|
+
|
713
|
+
def saved_name_split(name)
|
714
|
+
mf = name.match(/#{@options[:saved_script_filename_prefix]}_(?<time>[0-9\-]+)_(?<file>.+)_,_(?<block>.+)\.sh/)
|
715
|
+
return unless mf
|
640
716
|
|
641
|
-
|
717
|
+
@options[:block_name] = mf[:block].tap_inspect name: :options_block_name
|
718
|
+
@options[:filename] = mf[:file].gsub(FNR12, FNR11).tap_inspect name: :options_filename
|
642
719
|
end
|
643
720
|
|
644
721
|
def run_last_script
|
645
|
-
filename = Dir.glob(File.join(@options[:saved_script_folder],
|
646
|
-
|
647
|
-
|
648
|
-
mf = filename.match(/#{@options[:saved_script_filename_prefix]}_(?<time>[0-9\-]+)_(?<file>.+)_(?<block>.+)\.sh/)
|
722
|
+
filename = most_recent Dir.glob(File.join(@options[:saved_script_folder],
|
723
|
+
@options[:saved_script_glob]))
|
724
|
+
return unless filename
|
649
725
|
|
650
|
-
|
651
|
-
|
726
|
+
filename.tap_inspect name: filename
|
727
|
+
saved_name_split filename
|
652
728
|
@options[:save_executed_script] = false
|
653
729
|
select_and_approve_block
|
654
|
-
save_execution_output
|
655
|
-
output_execution_summary
|
656
730
|
end
|
657
731
|
|
658
732
|
def save_execution_output
|
659
733
|
return unless @options[:save_execution_output]
|
660
734
|
|
661
735
|
fne = File.basename(@options[:filename], '.*')
|
736
|
+
|
662
737
|
@options[:logged_stdout_filename] =
|
663
738
|
"#{[@options[:logged_stdout_filename_prefix], Time.now.utc.strftime('%F-%H-%M-%S'), fne,
|
664
739
|
@options[:block_name]].join('_')}.out.txt"
|
@@ -680,7 +755,9 @@ module MarkdownExec
|
|
680
755
|
|
681
756
|
return nil if block_labels.count.zero?
|
682
757
|
|
683
|
-
sel =
|
758
|
+
sel = prompt_with_quit pt, block_labels, per_page: opts[:select_page_height]
|
759
|
+
return nil if sel.nil?
|
760
|
+
|
684
761
|
label_block = blocks_in_file.select { |block| block[:label] == sel }.fetch(0, nil)
|
685
762
|
opts[:block_name] = @options[:block_name] = label_block[:name]
|
686
763
|
end
|
@@ -694,24 +771,29 @@ module MarkdownExec
|
|
694
771
|
if files.count == 1
|
695
772
|
files[0]
|
696
773
|
elsif files.count >= 2
|
697
|
-
|
774
|
+
prompt_with_quit opts[:prompt_select_md].to_s, files, per_page: opts[:select_page_height]
|
698
775
|
end
|
699
776
|
end
|
700
777
|
|
778
|
+
def select_recent_output
|
779
|
+
filename = prompt_with_quit @options[:prompt_select_output].to_s, list_recent_output,
|
780
|
+
per_page: @options[:select_page_height]
|
781
|
+
return unless filename.present?
|
782
|
+
|
783
|
+
`open #{filename} #{options[:output_viewer_options]}`
|
784
|
+
end
|
785
|
+
|
701
786
|
def select_recent_script
|
702
|
-
filename =
|
703
|
-
|
704
|
-
|
787
|
+
filename = prompt_with_quit @options[:prompt_select_md].to_s, list_recent_scripts,
|
788
|
+
per_page: @options[:select_page_height]
|
789
|
+
return if filename.nil?
|
705
790
|
|
706
|
-
|
707
|
-
@options[:filename] = "#{mf[:file]}.md" ### other extensions
|
791
|
+
saved_name_split filename
|
708
792
|
select_and_approve_block(
|
709
793
|
bash: true,
|
710
794
|
save_executed_script: false,
|
711
795
|
struct: true
|
712
796
|
)
|
713
|
-
save_execution_output
|
714
|
-
output_execution_summary
|
715
797
|
end
|
716
798
|
|
717
799
|
def sorted_keys(hash1)
|
@@ -722,22 +804,72 @@ module MarkdownExec
|
|
722
804
|
{ headings: headings, name: title, title: title }
|
723
805
|
end
|
724
806
|
|
807
|
+
def tab_completions(data = menu_data)
|
808
|
+
data.map do |item|
|
809
|
+
"--#{item[0]}" if item[0]
|
810
|
+
end.compact
|
811
|
+
end
|
812
|
+
|
725
813
|
def update_options(opts = {}, over: true)
|
726
814
|
if over
|
727
815
|
@options = @options.merge opts
|
728
816
|
else
|
729
817
|
@options.merge! opts
|
730
818
|
end
|
731
|
-
@options
|
819
|
+
@options.tap_inspect format: :yaml
|
820
|
+
end
|
821
|
+
|
822
|
+
def value_for_cli(value)
|
823
|
+
case value.class.to_s
|
824
|
+
when 'String'
|
825
|
+
"'#{value}'"
|
826
|
+
when 'FalseClass', 'TrueClass'
|
827
|
+
value ? '1' : '0'
|
828
|
+
when 'Integer'
|
829
|
+
value
|
830
|
+
else
|
831
|
+
value.to_s
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
def value_for_hash(value, default = nil)
|
836
|
+
return default if value.nil?
|
837
|
+
|
838
|
+
case value.class.to_s
|
839
|
+
when 'String', 'Integer', 'FalseClass', 'TrueClass'
|
840
|
+
value
|
841
|
+
when value.empty?
|
842
|
+
default
|
843
|
+
else
|
844
|
+
value.to_s
|
845
|
+
end
|
846
|
+
end
|
847
|
+
|
848
|
+
def value_for_yaml(value)
|
849
|
+
return default if value.nil?
|
850
|
+
|
851
|
+
case value.class.to_s
|
852
|
+
when 'String'
|
853
|
+
"'#{value}'"
|
854
|
+
when 'Integer'
|
855
|
+
value
|
856
|
+
when 'FalseClass', 'TrueClass'
|
857
|
+
value ? true : false
|
858
|
+
when value.empty?
|
859
|
+
default
|
860
|
+
else
|
861
|
+
value.to_s
|
862
|
+
end
|
732
863
|
end
|
733
864
|
|
734
865
|
def write_command_file(opts, required_blocks)
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
866
|
+
return unless opts[:save_executed_script]
|
867
|
+
|
868
|
+
opts[:saved_script_filename] = saved_name_make(opts)
|
869
|
+
@execute_script_filespec =
|
870
|
+
@options[:saved_filespec] =
|
871
|
+
File.join opts[:saved_script_folder], opts[:saved_script_filename]
|
872
|
+
|
741
873
|
dirname = File.dirname(@options[:saved_filespec])
|
742
874
|
Dir.mkdir dirname unless File.exist?(dirname)
|
743
875
|
File.write(@options[:saved_filespec], "#!/usr/bin/env bash\n" \
|
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.
|
4
|
+
version: 1.0.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: 2022-04-
|
11
|
+
date: 2022-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: open3
|
@@ -67,11 +67,13 @@ 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:
|
74
75
|
- mde
|
76
|
+
- tab_completion.sh
|
75
77
|
extensions: []
|
76
78
|
extra_rdoc_files: []
|
77
79
|
files:
|
@@ -91,6 +93,7 @@ files:
|
|
91
93
|
- bin/console
|
92
94
|
- bin/mde
|
93
95
|
- bin/setup
|
96
|
+
- bin/tab_completion.sh
|
94
97
|
- fixtures/bash1.md
|
95
98
|
- fixtures/bash2.md
|
96
99
|
- fixtures/exclude1.md
|
@@ -127,5 +130,5 @@ requirements: []
|
|
127
130
|
rubygems_version: 3.2.32
|
128
131
|
signing_key:
|
129
132
|
specification_version: 4
|
130
|
-
summary:
|
133
|
+
summary: Interactively select and execute fenced code blocks in markdown files.
|
131
134
|
test_files: []
|