markdown_exec 0.2.4 → 1.0.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 +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
|

|
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,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: []
|