markdown_exec 2.7.2 → 2.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -1
- data/Gemfile.lock +1 -1
- data/Rakefile +29 -11
- data/bats/block-type-opts.bats +23 -0
- data/bats/block-type-vars.bats +26 -0
- data/bats/block-types.bats +0 -36
- data/bats/line-wrapping.bats +8 -0
- data/bin/tab_completion.sh +1 -1
- data/docs/dev/block-type-opts.md +4 -1
- data/docs/dev/block-type-vars.md +11 -4
- data/docs/dev/line-wrapping.md +24 -0
- data/examples/link-blocks-vars.md +69 -41
- data/lib/colorize.rb +11 -37
- data/lib/format_table.rb +0 -1
- data/lib/hash_delegator.rb +89 -62
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +1 -2
- data/lib/menu.src.yml +1 -2
- data/lib/menu.yml +1 -1
- data/lib/ww.rb +5 -3
- metadata +7 -3
- /data/examples/{wrap.md → wrapped-blocks.md} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c35f2f729da73920db53053340bbe0ced75bfbb16ad59697fa6ba4016b62ae74
|
4
|
+
data.tar.gz: c20943723250feaa3e1b7218710cede9ebf4da4dd6eebf68584a805b9647b7d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 185f571fd39b4bdce955a455695413390b83c3635236871a83098bd595b184b5a79a2cd2b2778fb1fa795d658566237ed251e751fe1981a71aff192ce22da376
|
7
|
+
data.tar.gz: 19248dd05c973d9657362145826312fd2a07a7f6b4ad6834e623a19f289b35dc4d32c9c16401fc73a7e6309f4fc7ba9a5f63cc82a7db78299b623ea0d3b471f0
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,37 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.7.3] - 2025-01-29
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- Automatic loading of multiple Opts and Vars blocks when opening a document.
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
- Fix text displayed when text is wrapped to the next line.
|
12
|
+
- Handle and report failure of single tests.
|
13
|
+
|
14
|
+
## [2.7.2] - 2025-01-03
|
15
|
+
|
16
|
+
### Added
|
17
|
+
|
18
|
+
- Block name comparison in FCB class.
|
19
|
+
- Option for automatic shell block per document.
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
|
23
|
+
- Disable command substitution in comments.
|
24
|
+
- Fix the source reported by debug function ww0.
|
25
|
+
- Inverse the entire line to highlight the active menu line.
|
26
|
+
- Return single file if no globs in load block.
|
27
|
+
- Update the calculation and use of IDs for blocks used to retrieve the block selected from the menu.
|
28
|
+
|
29
|
+
## [2.7.1] - 2024-12-10
|
30
|
+
|
31
|
+
### Changed
|
32
|
+
|
33
|
+
- Register console dimensions prior to arguments.
|
34
|
+
|
3
35
|
## [2.7.0] - 2024-12-09
|
4
36
|
|
5
37
|
### Added
|
@@ -399,7 +431,7 @@ Rename options to match use.
|
|
399
431
|
These blocks can be hidden blocks and required in a script.
|
400
432
|
|
401
433
|
- Add a "wrap" fenced code block type to facilitate script generation.
|
402
|
-
See document `examples/
|
434
|
+
See document `examples/wrapped-blocks.md`.
|
403
435
|
These blocks are hidden and can be required by one or more blocks.
|
404
436
|
|
405
437
|
### Changed
|
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
@@ -74,14 +74,38 @@ task :clean do
|
|
74
74
|
system 'rm *.gem'
|
75
75
|
end
|
76
76
|
|
77
|
+
def execute_with_error_handling(iterator)
|
78
|
+
all_error_level = 0
|
79
|
+
all_failed_files = []
|
80
|
+
|
81
|
+
iterator.each do |item|
|
82
|
+
command = yield(item)
|
83
|
+
next unless command # Skip if command is nil
|
84
|
+
|
85
|
+
result = system(command)
|
86
|
+
error_level = $?.exitstatus
|
87
|
+
|
88
|
+
if error_level != 0
|
89
|
+
puts "Error: Command '#{command}' failed with exit status #{error_level}."
|
90
|
+
all_error_level = error_level
|
91
|
+
all_failed_files << command
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
if all_error_level != 0
|
96
|
+
puts "Error: #{all_failed_files.join(', ')} failed."
|
97
|
+
exit all_error_level
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
77
101
|
desc 'bats'
|
78
102
|
task :bats do
|
79
|
-
FileList['bats/**/*.bats']
|
80
|
-
next if %w[bats/bats.bats bats/fail.bats].include?(file)
|
103
|
+
execute_with_error_handling(FileList['bats/**/*.bats']) do |file|
|
104
|
+
next nil if %w[bats/bats.bats bats/fail.bats].include?(file)
|
81
105
|
|
82
106
|
# temporary clear WW to disable debugging
|
83
107
|
# WW pollutes output expected by BATS tests
|
84
|
-
|
108
|
+
"unset WW; bats #{file}"
|
85
109
|
end
|
86
110
|
end
|
87
111
|
|
@@ -118,14 +142,8 @@ task :minitest do
|
|
118
142
|
'./lib/dev/process_template.rb --test'
|
119
143
|
]
|
120
144
|
|
121
|
-
commands
|
122
|
-
|
123
|
-
error_level = $?.exitstatus
|
124
|
-
|
125
|
-
if error_level != 0
|
126
|
-
puts "Error: Command '#{command}' failed with exit status #{error_level}."
|
127
|
-
exit error_level
|
128
|
-
end
|
145
|
+
execute_with_error_handling(commands) do |command|
|
146
|
+
"bundle exec ruby #{command}"
|
129
147
|
end
|
130
148
|
end
|
131
149
|
task mini: %i[minitest]
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env bats
|
2
|
+
|
3
|
+
load 'test_helper'
|
4
|
+
|
5
|
+
# Type: Opts
|
6
|
+
|
7
|
+
@test 'Opts block - before' {
|
8
|
+
skip 'Fails because command executes after the block is processed'
|
9
|
+
spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-opts.md \
|
10
|
+
'BEFORE Species_menu_note_format: "AFTER %{line}" '
|
11
|
+
}
|
12
|
+
|
13
|
+
@test 'Opts block - after' {
|
14
|
+
spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-opts.md \
|
15
|
+
'[decorate-note]' \
|
16
|
+
'AFTER Species_menu_note_format: "AFTER %{line}"'
|
17
|
+
}
|
18
|
+
|
19
|
+
@test 'Opts block - show that menu has changed' {
|
20
|
+
skip 'Unable to show that menu has changed'
|
21
|
+
spec_mde_args_expect docs/dev/block-type-opts.md '[decorate-note]' \
|
22
|
+
'AFTER Species'
|
23
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env bats
|
2
|
+
|
3
|
+
load 'test_helper'
|
4
|
+
|
5
|
+
# Type: Vars
|
6
|
+
|
7
|
+
# includes output from automatic vars blocks
|
8
|
+
@test 'Vars block - auto load' {
|
9
|
+
BATS_OUTPUT_FILTER=A
|
10
|
+
spec_mde_args_expect docs/dev/block-type-vars.md show \
|
11
|
+
'Species = Not specified Genus = Not specified Species: Not specified VAULT:'
|
12
|
+
}
|
13
|
+
|
14
|
+
# includes output from assignment and from shell block
|
15
|
+
@test 'Vars block - set variable' {
|
16
|
+
BATS_OUTPUT_FILTER=A
|
17
|
+
spec_mde_args_expect docs/dev/block-type-vars.md '[set_vault_1]' show \
|
18
|
+
'Species = Not specified Genus = Not specified VAULT = 1 Species: Not specified VAULT: 1'
|
19
|
+
}
|
20
|
+
|
21
|
+
# handles invalid YAML in block
|
22
|
+
@test 'Vars block - invalid YAML' {
|
23
|
+
BATS_OUTPUT_FILTER=A
|
24
|
+
spec_mde_args_expect docs/dev/block-type-vars.md '[invalid_yaml]' show \
|
25
|
+
'Species = Not specified Genus = Not specified Species: Not specified VAULT:'
|
26
|
+
}
|
data/bats/block-types.bats
CHANGED
@@ -47,26 +47,6 @@ load 'test_helper'
|
|
47
47
|
run_mde_specs_md_args_expect_xansi '[VARIABLE1]' '(echo-VARIABLE1)' ' VARIABLE1: 1 VARIABLE1: 1'
|
48
48
|
}
|
49
49
|
|
50
|
-
# Type: Opts
|
51
|
-
|
52
|
-
@test 'Opts block - before' {
|
53
|
-
skip 'Fails because command executes after the block is processed'
|
54
|
-
spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-opts.md \
|
55
|
-
'BEFORE Species_menu_note_format: "AFTER %{line}" '
|
56
|
-
}
|
57
|
-
|
58
|
-
@test 'Opts block - after' {
|
59
|
-
spec_mde_xansi_dname_doc_blocks_expect docs/dev/block-type-opts.md \
|
60
|
-
'[decorate-note]' \
|
61
|
-
'AFTER Species_menu_note_format: "AFTER %{line}"'
|
62
|
-
}
|
63
|
-
|
64
|
-
@test 'Opts block - show that menu has changed' {
|
65
|
-
skip 'Unable to show that menu has changed'
|
66
|
-
spec_mde_args_expect docs/dev/block-type-opts.md '[decorate-note]' \
|
67
|
-
'AFTER Species'
|
68
|
-
}
|
69
|
-
|
70
50
|
# Type: Port
|
71
51
|
|
72
52
|
# includes output from assignment and from shell block
|
@@ -81,19 +61,3 @@ load 'test_helper'
|
|
81
61
|
spec_mde_args_expect docs/dev/block-type-port.md VAULT-is-export show \
|
82
62
|
' VAULT: This variable has not been set.'
|
83
63
|
}
|
84
|
-
|
85
|
-
# Type: Vars
|
86
|
-
|
87
|
-
# includes output from automatic vars block
|
88
|
-
@test 'Vars block - auto load' {
|
89
|
-
BATS_OUTPUT_FILTER=A
|
90
|
-
spec_mde_args_expect docs/dev/block-type-vars.md show \
|
91
|
-
'Species = Not specified Species: Not specified VAULT:'
|
92
|
-
}
|
93
|
-
|
94
|
-
# includes output from assignment and from shell block
|
95
|
-
@test 'Vars block - set variable' {
|
96
|
-
BATS_OUTPUT_FILTER=A
|
97
|
-
spec_mde_args_expect docs/dev/block-type-vars.md '[set_vault_1]' show \
|
98
|
-
'Species = Not specified VAULT = 1 Species: Not specified VAULT: 1'
|
99
|
-
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/usr/bin/env bats
|
2
|
+
|
3
|
+
load 'test_helper'
|
4
|
+
|
5
|
+
@test 'Text and Headings' {
|
6
|
+
spec_mde_xansi_dname_doc_blocks_expect docs/dev/line-wrapping.md \
|
7
|
+
" DEMO WRAPPING LONG LINES__MDE detects the screen's dimensions:_height (lines) and width (characters)__Normal document text is displayed as_disabled menu lines. The width of these_lines is limited according to the screen's_width.__Test Indented Lines__ Indented with two spaces, this line_ should wrap in an aesthetically pleasing_ way.__ Indented with a tab, this line should_ wrap in an aesthetically pleasing way.__ SPECIES GENUS FAMILY ORDER CLASS PHYLUM_ KINGDOM DOMAIN_species genus family order class phylum_kingdom domain"
|
8
|
+
}
|
data/bin/tab_completion.sh
CHANGED
data/docs/dev/block-type-opts.md
CHANGED
@@ -6,6 +6,9 @@ menu_note_format: "AFTER %{line}"
|
|
6
6
|
```opts :(document_opts)
|
7
7
|
menu_final_divider:
|
8
8
|
menu_for_saved_lines: false
|
9
|
+
```
|
10
|
+
/ Demonstrate multiple (document_opts) in a single file
|
11
|
+
```opts :(document_opts)
|
9
12
|
menu_initial_divider:
|
10
13
|
menu_note_format: "BEFORE %{line}"
|
11
|
-
```
|
14
|
+
```
|
data/docs/dev/block-type-vars.md
CHANGED
@@ -1,6 +1,15 @@
|
|
1
|
+
```vars :(document_vars)
|
2
|
+
Species: Not specified
|
3
|
+
```
|
4
|
+
```vars :(document_vars)
|
5
|
+
Genus: Not specified
|
6
|
+
```
|
1
7
|
```vars :[set_vault_1]
|
2
8
|
VAULT: 1
|
3
9
|
```
|
10
|
+
```vars :[invalid_yaml]
|
11
|
+
this is not yaml
|
12
|
+
```
|
4
13
|
```bash :show
|
5
14
|
echo "Species: $Species"
|
6
15
|
echo "VAULT: $VAULT"
|
@@ -8,8 +17,6 @@ echo "VAULT: $VAULT"
|
|
8
17
|
| Variable| Value
|
9
18
|
| -| -
|
10
19
|
| Species| ${Species}
|
20
|
+
| Genus| ${Genus}
|
11
21
|
| VAULT| ${VAULT}
|
12
|
-
@import bats-document-configuration.md
|
13
|
-
```vars :(document_vars)
|
14
|
-
Species: Not specified
|
15
|
-
```
|
22
|
+
@import bats-document-configuration.md
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Demo wrapping long lines
|
2
|
+
|
3
|
+
MDE detects the screen's dimensions: height (lines) and width (characters)
|
4
|
+
|
5
|
+
Normal document text is displayed as disabled menu lines. The width of these lines is limited according to the screen's width.
|
6
|
+
|
7
|
+
::: Test Indented Lines
|
8
|
+
|
9
|
+
Indented with two spaces, this line should wrap in an aesthetically pleasing way.
|
10
|
+
|
11
|
+
Indented with a tab, this line should wrap in an aesthetically pleasing way.
|
12
|
+
|
13
|
+
# species genus family order class phylum kingdom domain
|
14
|
+
## species genus family order class phylum kingdom domain
|
15
|
+
@import bats-document-configuration.md
|
16
|
+
```opts :(document_opts)
|
17
|
+
divider4_center: false
|
18
|
+
heading1_center: true
|
19
|
+
heading2_center: false
|
20
|
+
screen_width: 48
|
21
|
+
|
22
|
+
menu_note_match: "^(?<indent>[ \t]*)(?<line>(?!/)(?<text>.*?)(?<trailing>[ \t]*))?$"
|
23
|
+
|
24
|
+
```
|
@@ -1,59 +1,87 @@
|
|
1
|
-
# Demonstrate
|
2
|
-
|
3
|
-
```
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
pause_after_script_execution: true
|
1
|
+
# Demonstrate Setting Variables in the Inherited Lines
|
2
|
+
|
3
|
+
```link :select-a-folder +(select-a-folder)
|
4
|
+
eval: true
|
5
|
+
```
|
6
|
+
```bash :(select-a-folder)
|
7
|
+
echo "PT=$(osascript -e 'do shell script "echo " & quoted form of POSIX path of (choose folder with prompt "Please select a folder:")' 2>/dev/null)"
|
9
8
|
```
|
10
9
|
|
11
|
-
|
12
|
-
::: Select below to trigger. If it prints "VARIABLE1: 1", the Link block was processed.
|
10
|
+
This table displays the value of variables in the context of the current inherited lines. At first, the variable is empty unless it exists in the current shell environment.
|
13
11
|
|
14
12
|
| Variable| Value
|
15
13
|
| -| -
|
16
|
-
|
|
14
|
+
| SPECIES| ${SPECIES}
|
15
|
+
|
16
|
+
## Current Inherited Lines
|
17
|
+
|
18
|
+
```view
|
19
|
+
View the current inherited lines.
|
20
|
+
```
|
21
|
+
|
22
|
+
The inherited lines can also be displayed automatically within the menu by enabling this option:
|
23
|
+
|
24
|
+
```opts
|
25
|
+
menu_with_inherited_lines: true
|
26
|
+
```
|
27
|
+
|
28
|
+
## Setting Variables in the Inherited Lines
|
29
|
+
|
30
|
+
You can set environment variables in the inherited lines by adding shell expressions. For example, a line such as `SPECIES=Unknown` in the inherited lines defines a variable that can be used in the rest of the executed script.
|
31
|
+
|
32
|
+
Below are several ways to add such expressions to the inherited lines:
|
33
|
+
|
34
|
+
### Vars Block
|
35
|
+
|
36
|
+
This block (YAML) adds a variable and its value to the inherited lines:
|
37
|
+
|
38
|
+
```vars
|
39
|
+
SPECIES: Tapanuli Orangutan
|
40
|
+
```
|
41
|
+
|
42
|
+
### Link Block
|
43
|
+
|
44
|
+
This block (YAML) also adds a variable and its value to the inherited lines:
|
17
45
|
|
18
|
-
The block sets VARIABLE1.
|
19
|
-
For each environment variable in `vars`, append an inherited line that assigns the variable the specified value.
|
20
46
|
```link
|
21
47
|
vars:
|
22
|
-
|
48
|
+
SPECIES: Psychedelic Frogfish
|
23
49
|
```
|
24
50
|
|
25
|
-
|
26
|
-
This block "[bash_set_to_3]" is required below. It sets the variable "ALPHA".
|
27
|
-
```bash :[bash_set_to_3]
|
28
|
-
ALPHA=3
|
29
|
-
```
|
30
|
-
::: Select below to trigger. If it prints "ALPHA: 3", the Link block was processed.
|
31
|
-
These blocks require the *code* of the named shell block.
|
32
|
-
```link +[bash_set_to_3]
|
33
|
-
block: "(display_variable_ALPHA)"
|
34
|
-
```
|
35
|
-
```link +[bash_set_to_3]
|
36
|
-
next_block: "(display_variable_ALPHA)"
|
37
|
-
```
|
51
|
+
### Link+Bash Blocks
|
38
52
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
These blocks require the *output* of the execution of the code in the named shell block.
|
45
|
-
```link +[bash_set_to_4]
|
46
|
-
eval: true
|
47
|
-
block: "(display_variable_ALPHA)"
|
53
|
+
::: Adding Code to the Inherited Lines
|
54
|
+
|
55
|
+
This Link block (YAML) appends the Bash code defined in the referenced block to the inherited lines:
|
56
|
+
|
57
|
+
```link :add-bash-code +[bash_species]
|
48
58
|
```
|
49
|
-
|
59
|
+
```bash :[bash_species] @disable
|
60
|
+
SPECIES='Ruby Seadragon'
|
61
|
+
```
|
62
|
+
|
63
|
+
If necessary to extract environment variable values displayed in the menu, inherited lines are executed every time the menu displayed. Therefore, do add code that has unwanted side effects when executed multiple times.
|
64
|
+
|
65
|
+
::: Adding Evaluated Code Output to the Inherited Lines
|
66
|
+
|
67
|
+
This Link block (YAML) appends the output of the Bash code to the inherited lines. The Bash code is executed first to generate the output:
|
68
|
+
|
69
|
+
```link :add-evaluated-bash-code +[bash_species_code]
|
50
70
|
eval: true
|
51
|
-
next_block: "(display_variable_ALPHA)"
|
52
71
|
```
|
72
|
+
```bash :[bash_species_code] @disable
|
73
|
+
echo "SPECIES='Illacme tobini (Millipede)'"
|
74
|
+
```
|
53
75
|
|
54
76
|
| Variable| Value
|
55
77
|
| -| -
|
56
|
-
|
|
78
|
+
| SPECIES| ${SPECIES}
|
57
79
|
|
58
|
-
|
59
|
-
```
|
80
|
+
@import example-document-opts.md
|
81
|
+
```opts :(document_opts)
|
82
|
+
execute_in_own_window: false
|
83
|
+
menu_with_inherited_lines: false
|
84
|
+
output_execution_report: false
|
85
|
+
output_execution_summary: false
|
86
|
+
pause_after_script_execution: true
|
87
|
+
```
|
data/lib/colorize.rb
CHANGED
@@ -13,23 +13,15 @@ class String
|
|
13
13
|
# @return [String] The formatted string.
|
14
14
|
def method_missing(method_name, *args, &block)
|
15
15
|
case method_name.to_s
|
16
|
-
# when /^bg_rgb_/
|
17
|
-
# bytes = $'.split('_')
|
18
|
-
# bg_rgb_color(bytes[0..2].join(';'))
|
19
16
|
when /^fg_bg_rgb_/
|
20
|
-
pp [__LINE__, caller[0]]; binding.irb
|
21
17
|
bytes = $'.split('_')
|
22
18
|
fg_bg_rgb_color(bytes[0..2].join(';'), bytes[3..5].join(';'))
|
23
19
|
when /^fg_bg_rgbh_/
|
24
|
-
pp [__LINE__, caller[0]]; binding.irb
|
25
20
|
hex_to_fg_bg_rgb($')
|
26
21
|
when /^fg_rgb_/
|
27
|
-
pp [__LINE__, caller[0]]; binding.irb
|
28
22
|
fg_rgb_color($'.gsub('_', ';'))
|
29
23
|
when /^fg_rgbh_/
|
30
|
-
pp [__LINE__, caller[0]]; binding.irb
|
31
24
|
hex_to_rgb($')
|
32
|
-
|
33
25
|
when 'to_a', 'to_ary', 'to_hash', 'to_int', 'to_io', 'to_regexp'
|
34
26
|
nil
|
35
27
|
else
|
@@ -41,24 +33,14 @@ class String
|
|
41
33
|
#
|
42
34
|
# @return [String] The string wrapped in an ANSI control sequence.
|
43
35
|
def ansi_control_sequence
|
44
|
-
pp [__LINE__, caller[0]]; binding.irb
|
45
36
|
"\033[#{self}\033[0m"
|
46
37
|
end
|
47
38
|
|
48
|
-
# # Applies a 24-bit RGB background color to the string.
|
49
|
-
# #
|
50
|
-
# # @param rgb [String] The RGB color, expressed as a string like "1;2;3".
|
51
|
-
# # @return [String] The string with the applied RGB foreground color.
|
52
|
-
# def bg_rgb_color(rgb)
|
53
|
-
# "48;2;#{rgb}m#{self}".ansi_control_sequence
|
54
|
-
# end
|
55
|
-
|
56
39
|
# Applies a 24-bit RGB foreground color to the string.
|
57
40
|
#
|
58
41
|
# @param rgb [String] The RGB color, expressed as a string like "1;2;3".
|
59
42
|
# @return [String] The string with the applied RGB foreground color.
|
60
43
|
def fg_bg_rgb_color(fg_rgb, bg_rgb)
|
61
|
-
pp [__LINE__, caller[0]]; binding.irb
|
62
44
|
"38;2;#{fg_rgb}m\033[48;2;#{bg_rgb}m#{self}".ansi_control_sequence
|
63
45
|
end
|
64
46
|
|
@@ -67,7 +49,6 @@ class String
|
|
67
49
|
# @param rgb [String] The RGB color, expressed as a string like "1;2;3".
|
68
50
|
# @return [String] The string with the applied RGB foreground color.
|
69
51
|
def fg_rgb_color(rgb)
|
70
|
-
pp [__LINE__, caller[0]]; binding.irb
|
71
52
|
"38;2;#{rgb}m#{self}".ansi_control_sequence
|
72
53
|
end
|
73
54
|
|
@@ -76,7 +57,6 @@ class String
|
|
76
57
|
# @param hex_str [String] The RGB color, expressed as a hex string like "FF00FF".
|
77
58
|
# @return [String] The string with the applied RGB foreground color.
|
78
59
|
def hex_to_fg_bg_rgb(hex_str)
|
79
|
-
pp [__LINE__, caller[0]]; binding.irb
|
80
60
|
values = hex_str.split('_').map { |hex| hex.to_i(16).to_s }
|
81
61
|
fg_bg_rgb_color(
|
82
62
|
values[0..2].join(';'),
|
@@ -89,7 +69,6 @@ class String
|
|
89
69
|
# @param hex_str [String] The RGB color, expressed as a hex string like "FF00FF".
|
90
70
|
# @return [String] The string with the applied RGB foreground color.
|
91
71
|
def hex_to_rgb(hex_str)
|
92
|
-
pp [__LINE__, caller[0]]; binding.irb
|
93
72
|
fg_rgb_color(
|
94
73
|
hex_str.split('_').map { |hex| hex.to_i(16).to_s }.join(';')
|
95
74
|
)
|
@@ -99,7 +78,6 @@ class String
|
|
99
78
|
#
|
100
79
|
# @return [String] The original string.
|
101
80
|
def plain
|
102
|
-
pp [__LINE__, caller[0]]; binding.irb
|
103
81
|
self
|
104
82
|
end
|
105
83
|
|
@@ -126,20 +104,16 @@ class String
|
|
126
104
|
def violet; fg_rgbh_94_00_D3; end
|
127
105
|
def yellow; fg_rgbh_FF_FF_00; end
|
128
106
|
|
129
|
-
def x
|
130
|
-
pp [__LINE__, caller[1]]; binding.irb
|
131
|
-
end
|
132
|
-
|
133
107
|
# graphics modes
|
134
|
-
def bold;
|
135
|
-
def bold_italic;
|
136
|
-
def bold_underline;
|
137
|
-
def dim;
|
138
|
-
def italic;
|
139
|
-
def underline;
|
140
|
-
def underline_italic;
|
141
|
-
def blinking;
|
142
|
-
def inverse;
|
143
|
-
def hidden;
|
144
|
-
def strikethrough;
|
108
|
+
def bold; "\033[1m#{self}\033[22m"; end
|
109
|
+
def bold_italic; "\033[1m\033[3m#{self}\033[22m\033[23m"; end
|
110
|
+
def bold_underline; "\033[1m\033[4m#{self}\033[22m\033[24m"; end
|
111
|
+
def dim; "\033[2m#{self}\033[22m"; end
|
112
|
+
def italic; "\033[3m#{self}\033[23m"; end
|
113
|
+
def underline; "\033[4m#{self}\033[24m"; end
|
114
|
+
def underline_italic; "\033[4m\033[3m#{self}\033[23m\033[24m"; end
|
115
|
+
def blinking; "\033[5m#{self}\033[25m"; end
|
116
|
+
def inverse; "\033[7m#{self}\033[27m"; end
|
117
|
+
def hidden; "\033[8m#{self}\033[28m"; end
|
118
|
+
def strikethrough; "\033[9m#{self}\033[29m"; end
|
145
119
|
end
|
data/lib/format_table.rb
CHANGED
data/lib/hash_delegator.rb
CHANGED
@@ -91,6 +91,10 @@ module HashDelegatorSelf
|
|
91
91
|
blocks.find { |item| item.send(msg) == value } || default
|
92
92
|
end
|
93
93
|
|
94
|
+
def block_select(blocks, msg, value, default = nil)
|
95
|
+
blocks.select { |item| item.send(msg) == value }
|
96
|
+
end
|
97
|
+
|
94
98
|
def code_merge(*bodies)
|
95
99
|
merge_lists(*bodies)
|
96
100
|
end
|
@@ -979,16 +983,19 @@ module MarkdownExec
|
|
979
983
|
|
980
984
|
# sets ENV
|
981
985
|
def code_from_vars_block_to_set_environment_variables(selected)
|
982
|
-
code_lines = []
|
983
|
-
YAML.load(selected.body.join("\n"))
|
984
|
-
|
985
|
-
|
986
|
+
code_lines = []
|
987
|
+
case data = YAML.load(selected.body.join("\n"))
|
988
|
+
when Hash
|
989
|
+
data.each do |key, value|
|
990
|
+
ENV[key] = value.to_s
|
991
|
+
code_lines.push "#{key}=#{Shellwords.escape(value)}"
|
986
992
|
|
987
|
-
|
993
|
+
next unless @delegate_object[:menu_vars_set_format].present?
|
988
994
|
|
989
|
-
|
990
|
-
|
991
|
-
|
995
|
+
formatted_string = format(@delegate_object[:menu_vars_set_format],
|
996
|
+
{ key: key, value: value })
|
997
|
+
print string_send_color(formatted_string, :menu_vars_set_color)
|
998
|
+
end
|
992
999
|
end
|
993
1000
|
code_lines
|
994
1001
|
end
|
@@ -1232,11 +1239,12 @@ module MarkdownExec
|
|
1232
1239
|
wrap: nil,
|
1233
1240
|
fcb: nil
|
1234
1241
|
)
|
1235
|
-
|
1242
|
+
ww 'match_data', match_data
|
1243
|
+
line_cap = NamedCaptureExtractor.extract_named_group_match_data(match_data)
|
1236
1244
|
# replace tabs in indent
|
1237
1245
|
line_cap[:indent] ||= ''
|
1238
1246
|
line_cap[:indent] = line_cap[:indent].dup if line_cap[:indent].frozen?
|
1239
|
-
line_cap[:indent].gsub!("\t", ' ')
|
1247
|
+
line_cap[:indent].gsub!("\t", ' ') # TAB_SIZE = 4
|
1240
1248
|
# replace tabs in text
|
1241
1249
|
line_cap[:text] ||= ''
|
1242
1250
|
line_cap[:text] = line_cap[:text].dup if line_cap[:text].frozen?
|
@@ -1264,6 +1272,7 @@ module MarkdownExec
|
|
1264
1272
|
end
|
1265
1273
|
end
|
1266
1274
|
|
1275
|
+
use_fcb = !fcb.nil? # fcb only for the first record if any
|
1267
1276
|
line_caps.each_with_index do |line_obj, index|
|
1268
1277
|
next if line_obj[:text].nil?
|
1269
1278
|
|
@@ -1287,7 +1296,7 @@ module MarkdownExec
|
|
1287
1296
|
|
1288
1297
|
line_obj[:line] = line_obj[:indent] + line_obj[:text]
|
1289
1298
|
|
1290
|
-
if
|
1299
|
+
if !use_fcb
|
1291
1300
|
fcb = FCB.new(
|
1292
1301
|
center: center,
|
1293
1302
|
chrome: true,
|
@@ -1321,6 +1330,7 @@ module MarkdownExec
|
|
1321
1330
|
fcb.oname = line_obj[:text]
|
1322
1331
|
fcb.text = line_obj[:text]
|
1323
1332
|
fcb.type = type
|
1333
|
+
use_fcb = false # next line is new record
|
1324
1334
|
end
|
1325
1335
|
|
1326
1336
|
blocks.push fcb
|
@@ -1956,7 +1966,7 @@ module MarkdownExec
|
|
1956
1966
|
[exit_prompt] + dirs.sort.map do |file|
|
1957
1967
|
{ name: format(
|
1958
1968
|
block_data['view'] || view,
|
1959
|
-
NamedCaptureExtractor.
|
1969
|
+
NamedCaptureExtractor.extract_named_group_match_data(
|
1960
1970
|
file.match(
|
1961
1971
|
Regexp.new(block_data['filename_pattern'] ||
|
1962
1972
|
filename_pattern)
|
@@ -2240,7 +2250,6 @@ module MarkdownExec
|
|
2240
2250
|
key_format: '${%s}',
|
2241
2251
|
pattern: nil
|
2242
2252
|
)
|
2243
|
-
# defined($x) ? '' : ($x = 1; pp [__LINE__, caller.deref])
|
2244
2253
|
pattern ||= options_variable_expression_regexp
|
2245
2254
|
return if pattern.nil?
|
2246
2255
|
|
@@ -2553,20 +2562,29 @@ module MarkdownExec
|
|
2553
2562
|
label_format_above = @delegate_object[:shell_code_label_format_above]
|
2554
2563
|
label_format_below = @delegate_object[:shell_code_label_format_below]
|
2555
2564
|
|
2556
|
-
[
|
2557
|
-
|
2558
|
-
|
2559
|
-
|
2560
|
-
|
2561
|
-
|
2562
|
-
|
2563
|
-
|
2564
|
-
|
2565
|
-
|
2566
|
-
|
2567
|
-
|
2568
|
-
|
2569
|
-
|
2565
|
+
([
|
2566
|
+
label_format_above.present? ?
|
2567
|
+
format(
|
2568
|
+
label_format_above,
|
2569
|
+
block_source.merge({ block_name: selected.pub_name })
|
2570
|
+
) : nil
|
2571
|
+
] +
|
2572
|
+
output_lines.map do |line|
|
2573
|
+
re = Regexp.new(link_block_data.fetch('pattern', '(?<line>.*)'))
|
2574
|
+
next unless re =~ line
|
2575
|
+
|
2576
|
+
re.gsub_format(
|
2577
|
+
line,
|
2578
|
+
link_block_data.fetch('format', '%{line}')
|
2579
|
+
)
|
2580
|
+
end +
|
2581
|
+
[
|
2582
|
+
label_format_below.present? ?
|
2583
|
+
format(
|
2584
|
+
label_format_below,
|
2585
|
+
block_source.merge({ block_name: selected.pub_name })
|
2586
|
+
) : nil
|
2587
|
+
]).compact
|
2570
2588
|
end
|
2571
2589
|
|
2572
2590
|
def link_history_push_and_next(
|
@@ -2641,43 +2659,23 @@ module MarkdownExec
|
|
2641
2659
|
return
|
2642
2660
|
end
|
2643
2661
|
|
2644
|
-
|
2645
|
-
return
|
2662
|
+
blocks = HashDelegator.block_select(all_blocks, :oname, block_name)
|
2663
|
+
return if blocks.empty?
|
2646
2664
|
|
2647
|
-
|
2648
|
-
|
2649
|
-
|
2665
|
+
update_menu_base(
|
2666
|
+
blocks.each.with_object({}) do |block, merged_options|
|
2667
|
+
options_state = read_show_options_and_trigger_reuse(
|
2668
|
+
mdoc: mdoc,
|
2669
|
+
selected: block
|
2670
|
+
)
|
2671
|
+
merged_options.merge!(options_state.options)
|
2672
|
+
end
|
2650
2673
|
)
|
2651
|
-
update_menu_base(options_state.options)
|
2652
2674
|
|
2653
2675
|
@opts_most_recent_filename = @delegate_object[:filename]
|
2654
2676
|
true
|
2655
2677
|
end
|
2656
2678
|
|
2657
|
-
def load_document_shell_block(all_blocks, mdoc: nil)
|
2658
|
-
block_name = @delegate_object[:document_load_shell_block_name]
|
2659
|
-
unless block_name.present? &&
|
2660
|
-
@shell_most_recent_filename != @delegate_object[:filename]
|
2661
|
-
return
|
2662
|
-
end
|
2663
|
-
|
2664
|
-
fcb = HashDelegator.block_find(all_blocks, :oname, block_name)
|
2665
|
-
return unless fcb
|
2666
|
-
|
2667
|
-
@shell_most_recent_filename = @delegate_object[:filename]
|
2668
|
-
|
2669
|
-
if mdoc
|
2670
|
-
mdoc.collect_recursively_required_code(
|
2671
|
-
anyname: fcb.pub_name,
|
2672
|
-
label_format_above: @delegate_object[:shell_code_label_format_above],
|
2673
|
-
label_format_below: @delegate_object[:shell_code_label_format_below],
|
2674
|
-
block_source: block_source
|
2675
|
-
)[:code]
|
2676
|
-
else
|
2677
|
-
fcb.body
|
2678
|
-
end
|
2679
|
-
end
|
2680
|
-
|
2681
2679
|
def load_auto_vars_block(all_blocks,
|
2682
2680
|
block_name: @delegate_object[:document_load_vars_block_name])
|
2683
2681
|
unless block_name.present? &&
|
@@ -2685,11 +2683,16 @@ module MarkdownExec
|
|
2685
2683
|
return
|
2686
2684
|
end
|
2687
2685
|
|
2688
|
-
|
2689
|
-
return
|
2686
|
+
blocks = HashDelegator.block_select(all_blocks, :oname, block_name)
|
2687
|
+
return if blocks.empty?
|
2690
2688
|
|
2691
2689
|
@vars_most_recent_filename = @delegate_object[:filename]
|
2692
|
-
|
2690
|
+
|
2691
|
+
(blocks.each.with_object([]) do |block, merged_options|
|
2692
|
+
merged_options.push(
|
2693
|
+
code_from_vars_block_to_set_environment_variables(block)
|
2694
|
+
)
|
2695
|
+
end).to_a
|
2693
2696
|
end
|
2694
2697
|
|
2695
2698
|
def load_cli_or_user_selected_block(all_blocks: [], menu_blocks: [],
|
@@ -2712,6 +2715,30 @@ module MarkdownExec
|
|
2712
2715
|
SelectedBlockMenuState.new(block, source, state)
|
2713
2716
|
end
|
2714
2717
|
|
2718
|
+
def load_document_shell_block(all_blocks, mdoc: nil)
|
2719
|
+
block_name = @delegate_object[:document_load_shell_block_name]
|
2720
|
+
unless block_name.present? &&
|
2721
|
+
@shell_most_recent_filename != @delegate_object[:filename]
|
2722
|
+
return
|
2723
|
+
end
|
2724
|
+
|
2725
|
+
fcb = HashDelegator.block_find(all_blocks, :oname, block_name)
|
2726
|
+
return unless fcb
|
2727
|
+
|
2728
|
+
@shell_most_recent_filename = @delegate_object[:filename]
|
2729
|
+
|
2730
|
+
if mdoc
|
2731
|
+
mdoc.collect_recursively_required_code(
|
2732
|
+
anyname: fcb.pub_name,
|
2733
|
+
label_format_above: @delegate_object[:shell_code_label_format_above],
|
2734
|
+
label_format_below: @delegate_object[:shell_code_label_format_below],
|
2735
|
+
block_source: block_source
|
2736
|
+
)[:code]
|
2737
|
+
else
|
2738
|
+
fcb.body
|
2739
|
+
end
|
2740
|
+
end
|
2741
|
+
|
2715
2742
|
# format + glob + select for file in load block
|
2716
2743
|
# name has references to ENV vars and doc and batch vars
|
2717
2744
|
# incl. timestamp
|
@@ -3839,10 +3866,10 @@ module MarkdownExec
|
|
3839
3866
|
shell: fcb_title_groups.fetch(:shell, ''),
|
3840
3867
|
start_line: line,
|
3841
3868
|
stdin: if (tn = rest.match(/<(?<type>\$)?(?<name>[A-Za-z_-]\S+)/))
|
3842
|
-
NamedCaptureExtractor.
|
3869
|
+
NamedCaptureExtractor.extract_named_group_match_data(tn)
|
3843
3870
|
end,
|
3844
3871
|
stdout: if (tn = rest.match(/>(?<type>\$)?(?<name>[\w.\-]+)/))
|
3845
|
-
NamedCaptureExtractor.
|
3872
|
+
NamedCaptureExtractor.extract_named_group_match_data(tn)
|
3846
3873
|
end,
|
3847
3874
|
title: title,
|
3848
3875
|
type: fcb_title_groups.fetch(:type, ''),
|
data/lib/markdown_exec.rb
CHANGED
@@ -19,7 +19,6 @@ require_relative 'ansi_formatter'
|
|
19
19
|
require_relative 'cached_nested_file_reader'
|
20
20
|
require_relative 'cli'
|
21
21
|
require_relative 'color_scheme'
|
22
|
-
require_relative 'colorize'
|
23
22
|
require_relative 'directory_searcher'
|
24
23
|
require_relative 'env'
|
25
24
|
require_relative 'exceptions'
|
@@ -95,7 +94,7 @@ class NamedCaptureExtractor
|
|
95
94
|
str&.match(regexp)&.named_captures&.transform_keys(&:to_sym)
|
96
95
|
end
|
97
96
|
|
98
|
-
def self.
|
97
|
+
def self.extract_named_group_match_data(match_data)
|
99
98
|
match_data&.named_captures&.transform_keys(&:to_sym)
|
100
99
|
end
|
101
100
|
end
|
data/lib/menu.src.yml
CHANGED
@@ -904,11 +904,10 @@
|
|
904
904
|
:procname: val_as_str
|
905
905
|
|
906
906
|
## lines that start with "/" are comments (hidden), not notes (visible)
|
907
|
-
# - :default: "^(?<indent>[ \t]*)(?<line>(?!/)(?<text>.*?)(?<trailing>[ \t]*))?$"
|
908
907
|
- :opt_name: menu_note_match
|
909
908
|
:env_var: MDE_MENU_NOTE_MATCH
|
910
909
|
:description: Pattern for notes in block selection menu
|
911
|
-
:default: "^(?<
|
910
|
+
:default: "^(?<indent>[ \t]*)(?<line>(?!/)(?<text>.*?)(?<trailing>[ \t]*))?$"
|
912
911
|
:procname: val_as_str
|
913
912
|
|
914
913
|
- :opt_name: menu_option_back_name
|
data/lib/menu.yml
CHANGED
@@ -766,7 +766,7 @@
|
|
766
766
|
- :opt_name: menu_note_match
|
767
767
|
:env_var: MDE_MENU_NOTE_MATCH
|
768
768
|
:description: Pattern for notes in block selection menu
|
769
|
-
:default: "^(?<
|
769
|
+
:default: "^(?<indent>[ \t]*)(?<line>(?!/)(?<text>.*?)(?<trailing>[ \t]*))?$"
|
770
770
|
:procname: val_as_str
|
771
771
|
- :opt_name: menu_option_back_name
|
772
772
|
:env_var: MDE_MENU_OPTION_BACK_NAME
|
data/lib/ww.rb
CHANGED
@@ -15,7 +15,7 @@ if $debug && ENV['WW_MINIMUM'].nil?
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def ww(*objs, **kwargs)
|
18
|
-
return unless $debug
|
18
|
+
return objs.size == 1 ? objs.first : objs unless $debug
|
19
19
|
|
20
20
|
ww0(*objs, **kwargs.merge(locations: caller_locations))
|
21
21
|
end
|
@@ -24,7 +24,7 @@ def ww0(*objs,
|
|
24
24
|
category: nil,
|
25
25
|
full_backtrace: false,
|
26
26
|
level: :debug,
|
27
|
-
locations: caller_locations
|
27
|
+
locations: caller_locations,
|
28
28
|
log_file: nil,
|
29
29
|
output: $stderr,
|
30
30
|
single_line: false,
|
@@ -70,11 +70,13 @@ def ww0(*objs,
|
|
70
70
|
output.flush
|
71
71
|
|
72
72
|
# Optionally log to a file
|
73
|
-
return unless log_file
|
73
|
+
return objs.size == 1 ? objs.first : objs unless log_file
|
74
74
|
|
75
75
|
File.open(log_file, 'a') do |file|
|
76
76
|
file.puts(formatted_message)
|
77
77
|
end
|
78
|
+
|
79
|
+
objs.size == 1 ? objs.first : objs
|
78
80
|
end
|
79
81
|
|
80
82
|
class Array
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: markdown_exec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.7.
|
4
|
+
version: 2.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fareed Stevenson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-01-
|
11
|
+
date: 2025-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: clipboard
|
@@ -107,6 +107,8 @@ files:
|
|
107
107
|
- assets/select_a_block.png
|
108
108
|
- assets/select_a_file.png
|
109
109
|
- bats/bats.bats
|
110
|
+
- bats/block-type-opts.bats
|
111
|
+
- bats/block-type-vars.bats
|
110
112
|
- bats/block-types.bats
|
111
113
|
- bats/border.bats
|
112
114
|
- bats/cli.bats
|
@@ -115,6 +117,7 @@ files:
|
|
115
117
|
- bats/fail.bats
|
116
118
|
- bats/history.bats
|
117
119
|
- bats/import.bats
|
120
|
+
- bats/line-wrapping.bats
|
118
121
|
- bats/markup.bats
|
119
122
|
- bats/mde.bats
|
120
123
|
- bats/options-collapse.bats
|
@@ -143,6 +146,7 @@ files:
|
|
143
146
|
- docs/dev/document-shell.md
|
144
147
|
- docs/dev/import-missing.md
|
145
148
|
- docs/dev/import.md
|
149
|
+
- docs/dev/line-wrapping.md
|
146
150
|
- docs/dev/linked-file.md
|
147
151
|
- docs/dev/load1.sh
|
148
152
|
- docs/dev/load_code.md
|
@@ -201,7 +205,7 @@ files:
|
|
201
205
|
- examples/variable-expansion-save-block.md
|
202
206
|
- examples/variable-expansion.md
|
203
207
|
- examples/vars-blocks.md
|
204
|
-
- examples/
|
208
|
+
- examples/wrapped-blocks.md
|
205
209
|
- lib/ansi_formatter.rb
|
206
210
|
- lib/ansi_string.rb
|
207
211
|
- lib/argument_processor.rb
|
File without changes
|