markdown_exec 2.0.3.2 → 2.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/bin/tab_completion.sh +11 -3
- data/examples/linked.md +23 -3
- data/lib/directory_searcher.rb +22 -22
- data/lib/find_files.rb +50 -7
- data/lib/hash_delegator.rb +115 -53
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +87 -31
- data/lib/menu.src.yml +15 -1
- data/lib/menu.yml +14 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eadeecd7019d53202aabe57d9486ee616826e6b5f42fce0fa24f8e377c1b50e5
|
4
|
+
data.tar.gz: cde007bddd4821263045eeba415cc1e2f42591d03294fc678c4093384373146b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a4a3a36d420c41403be33dbc7ac8e53f446dac53ba3ce8e9cd2fafb1ff0c1026aa1df633f6d79e1742ea11a07f71bd3f64df95f772798ff4624b8c36a8f93b2
|
7
|
+
data.tar.gz: 1acc6cb2bf716b30a1ab8037ad0e43ff3646b23b991cd1bd9d31b1aad37ccf6ae97bd01eaeecc57e644ceb580a9aa9bf61742075777a528ffc180a43a955ccb1
|
data/.rubocop.yml
CHANGED
@@ -16,6 +16,7 @@ Layout/LineContinuationLeadingSpace:
|
|
16
16
|
Layout/LineLength: # 2024-01-21 temp disable
|
17
17
|
Enabled: false
|
18
18
|
Max: 96
|
19
|
+
Max: 120
|
19
20
|
|
20
21
|
Lint/Debugger:
|
21
22
|
Enabled: false
|
@@ -83,6 +84,9 @@ Style/MixinUsage:
|
|
83
84
|
Style/MultilineBlockChain:
|
84
85
|
Enabled: false
|
85
86
|
|
87
|
+
Style/OpenStructUse:
|
88
|
+
Enabled: false
|
89
|
+
|
86
90
|
Style/PerlBackrefs: # Prefer ::Regexp.last_match.post_match over $'.
|
87
91
|
Enabled: false
|
88
92
|
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/bin/tab_completion.sh
CHANGED
@@ -13,7 +13,7 @@ __filedirs_all()
|
|
13
13
|
}
|
14
14
|
|
15
15
|
_mde_echo_version() {
|
16
|
-
echo "2.0.
|
16
|
+
echo "2.0.4"
|
17
17
|
}
|
18
18
|
|
19
19
|
_mde() {
|
@@ -66,6 +66,10 @@ _mde() {
|
|
66
66
|
|
67
67
|
--list-count) COMPREPLY="32"; return 0 ;;
|
68
68
|
|
69
|
+
--open) COMPREPLY="''"; return 0 ;;
|
70
|
+
|
71
|
+
-o) COMPREPLY="''"; return 0 ;;
|
72
|
+
|
69
73
|
--output-execution-summary) COMPREPLY="0"; return 0 ;;
|
70
74
|
|
71
75
|
--output-script) COMPREPLY="0"; return 0 ;;
|
@@ -98,7 +102,7 @@ _mde() {
|
|
98
102
|
# present matching option names
|
99
103
|
#
|
100
104
|
if [[ ${cur} == -* ]] ; then
|
101
|
-
opts=("--block-name" "--config" "--debug" "--dump-dump-delegate-object" "--dump-blocks-in-file" "--dump-dump-inherited-block_names" "--dump-dump-inherited-dependencies" "--dump-dump-inherited-lines" "--dump-menu-blocks" "--dump-selected-block" "--exit" "--filename" "--find" "--find-path" "--help" "--how" "--list-blocks" "--list-count" "--list-default-env" "--list-default-yaml" "--list-docs" "--list-recent-output" "--list-recent-scripts" "--output-execution-summary" "--output-script" "--output-stdout" "--path" "--pwd" "--run-last-script" "--save-executed-script" "--save-execution-output" "--saved-script-folder" "--saved-stdout-folder" "--select-recent-output" "--select-recent-script" "--tab-completions" "--user-must-approve" "--version" "--display-level")
|
105
|
+
opts=("--block-name" "--config" "--debug" "--dump-dump-delegate-object" "--dump-blocks-in-file" "--dump-dump-inherited-block_names" "--dump-dump-inherited-dependencies" "--dump-dump-inherited-lines" "--dump-menu-blocks" "--dump-selected-block" "--exit" "--filename" "--find" "--find-path" "--help" "--how" "--list-blocks" "--list-count" "--list-default-env" "--list-default-yaml" "--list-docs" "--list-recent-output" "--list-recent-scripts" "--open" "--output-execution-summary" "--output-script" "--output-stdout" "--path" "--pwd" "--run-last-script" "--save-executed-script" "--save-execution-output" "--saved-script-folder" "--saved-stdout-folder" "--select-recent-output" "--select-recent-script" "--tab-completions" "--user-must-approve" "--version" "--display-level")
|
102
106
|
COMPREPLY=( $(compgen -W "$(printf "'%s' " "${opts[@]}")" -- "${cur}") )
|
103
107
|
|
104
108
|
return 0
|
@@ -151,6 +155,10 @@ _mde() {
|
|
151
155
|
|
152
156
|
--list-count) COMPREPLY=".INT.1-."; return 0 ;;
|
153
157
|
|
158
|
+
--open) COMPREPLY=".OPEN."; return 0 ;;
|
159
|
+
|
160
|
+
-o) COMPREPLY=".OPEN."; return 0 ;;
|
161
|
+
|
154
162
|
--output-execution-summary) COMPREPLY=".BOOL."; return 0 ;;
|
155
163
|
|
156
164
|
--output-script) COMPREPLY=".BOOL."; return 0 ;;
|
@@ -186,4 +194,4 @@ _mde() {
|
|
186
194
|
|
187
195
|
complete -o filenames -o nospace -F _mde mde
|
188
196
|
# _mde_echo_version
|
189
|
-
# echo "Updated: 2024-04-
|
197
|
+
# echo "Updated: 2024-04-23 01:25:22 UTC"
|
data/examples/linked.md
CHANGED
@@ -9,7 +9,29 @@ user_must_approve: false
|
|
9
9
|
block: (display_variable)
|
10
10
|
eval: true
|
11
11
|
```
|
12
|
-
|
12
|
+
Block name with all chars.
|
13
|
+
/ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
14
|
+
/ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
|
15
|
+
```link :!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
|
16
|
+
file: examples/linked2.md
|
17
|
+
block: show_vars
|
18
|
+
vars:
|
19
|
+
page2_var_via_environment: for_page2_from_page1_via_current_environment
|
20
|
+
```
|
21
|
+
```link :¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
|
22
|
+
file: examples/linked2.md
|
23
|
+
block: show_vars
|
24
|
+
vars:
|
25
|
+
page2_var_via_environment: for_page2_from_page1_via_current_environment
|
26
|
+
```
|
27
|
+
Block with no title is displayed correctly in a single line (for a Bash comment).
|
28
|
+
```link
|
29
|
+
file: examples/linked2.md
|
30
|
+
block: show_vars
|
31
|
+
vars:
|
32
|
+
page2_var_via_environment: for_page2_from_page1_via_current_environment
|
33
|
+
```
|
34
|
+
Spaces in variable value are unchanged.
|
13
35
|
```link :link_with_vars_with_spaces
|
14
36
|
vars:
|
15
37
|
test: "1 2 3"
|
@@ -124,11 +146,9 @@ load: examples/fail*
|
|
124
146
|
```link :load_glob_with_format
|
125
147
|
load: "%{home}/examples/load*.sh"
|
126
148
|
```
|
127
|
-
|
128
149
|
```link :save_glob_load*
|
129
150
|
save: examples/*.sh
|
130
151
|
```
|
131
|
-
|
132
152
|
```link :save_glob_*
|
133
153
|
save: examples/*.sh
|
134
154
|
```
|
data/lib/directory_searcher.rb
CHANGED
@@ -110,7 +110,7 @@ class DirectorySearcher
|
|
110
110
|
|
111
111
|
# Searches for the pattern in directory names.
|
112
112
|
# @return [Array<String>] List of matching directory names.
|
113
|
-
def
|
113
|
+
def find_directory_names
|
114
114
|
match_dirs = []
|
115
115
|
@paths.each do |path|
|
116
116
|
Find.find(path) do |p|
|
@@ -123,7 +123,7 @@ class DirectorySearcher
|
|
123
123
|
|
124
124
|
# Searches for the pattern in file names.
|
125
125
|
# @return [Array<String>] List of matching file names.
|
126
|
-
def
|
126
|
+
def find_file_names
|
127
127
|
match_files = []
|
128
128
|
@paths.each do |path|
|
129
129
|
Find.find(path) do |p|
|
@@ -147,7 +147,7 @@ class DirectorySearcher
|
|
147
147
|
|
148
148
|
# Searches for the pattern in the contents of the files and returns matches along with their file paths and line numbers.
|
149
149
|
# @return [Hash] A hash where each key is a file path and each value is an array of hashes with :line_number and :line keys.
|
150
|
-
def
|
150
|
+
def find_file_contents
|
151
151
|
match_details = {}
|
152
152
|
|
153
153
|
@paths.each do |path|
|
@@ -178,7 +178,7 @@ class DirectorySearcher
|
|
178
178
|
|
179
179
|
# # Searches for the pattern in the contents of the files.
|
180
180
|
# # @return [Array<String>] List of matching lines from files.
|
181
|
-
# def
|
181
|
+
# def find_file_contents
|
182
182
|
# match_lines = []
|
183
183
|
# @paths.each do |path|
|
184
184
|
# Find.find(path) do |p|
|
@@ -219,22 +219,22 @@ if $PROGRAM_NAME == __FILE__
|
|
219
219
|
@searcher = DirectorySearcher.new(@pattern, @paths)
|
220
220
|
end
|
221
221
|
|
222
|
-
# Test
|
223
|
-
def
|
222
|
+
# Test find_directory_names method
|
223
|
+
def test_find_directory_names
|
224
224
|
# Add assertions based on your test directory structure and expected results
|
225
|
-
assert_equal [], @searcher.
|
225
|
+
assert_equal [], @searcher.find_directory_names
|
226
226
|
end
|
227
227
|
|
228
|
-
# Test
|
229
|
-
def
|
228
|
+
# Test find_file_names method
|
229
|
+
def test_find_file_names
|
230
230
|
# Add assertions based on your test directory structure and expected results
|
231
|
-
assert_equal [], @searcher.
|
231
|
+
assert_equal [], @searcher.find_file_names
|
232
232
|
end
|
233
233
|
|
234
|
-
# Test
|
235
|
-
def
|
234
|
+
# Test find_file_contents method
|
235
|
+
def test_find_file_contents
|
236
236
|
# Add assertions based on your test directory structure and expected results
|
237
|
-
assert_equal ({}), @searcher.
|
237
|
+
assert_equal ({}), @searcher.find_file_contents
|
238
238
|
end
|
239
239
|
end
|
240
240
|
|
@@ -249,26 +249,26 @@ if $PROGRAM_NAME == __FILE__
|
|
249
249
|
filename_glob: @filename_glob)
|
250
250
|
end
|
251
251
|
|
252
|
-
# Test
|
253
|
-
def
|
252
|
+
# Test find_directory_names method for 'spec'
|
253
|
+
def test_find_directory_names_for_spec
|
254
254
|
# Replace with actual expected directory names containing 'spec'
|
255
255
|
expected_dirs = ['./spec']
|
256
|
-
assert_equal expected_dirs, @searcher_spec.
|
256
|
+
assert_equal expected_dirs, @searcher_spec.find_directory_names
|
257
257
|
end
|
258
258
|
|
259
|
-
# Test
|
260
|
-
def
|
259
|
+
# Test find_file_names method for 'spec'
|
260
|
+
def test_find_file_names_for_spec
|
261
261
|
# Replace with actual expected file names containing 'spec'
|
262
262
|
expected_files = ['./spec/cli_spec.rb', './spec/env_spec.rb',
|
263
263
|
'./spec/markdown_exec_spec.rb', './spec/tap_spec.rb']
|
264
|
-
assert_equal expected_files, @searcher_spec.
|
264
|
+
assert_equal expected_files, @searcher_spec.find_file_names
|
265
265
|
end
|
266
266
|
|
267
|
-
# # Test
|
268
|
-
# def
|
267
|
+
# # Test find_file_contents method for 'spec'
|
268
|
+
# def test_find_file_contents_for_spec
|
269
269
|
# # Replace with actual expected lines containing 'spec'
|
270
270
|
# expected_lines = {['Line with spec 1', 'Line with spec 2']}
|
271
|
-
# assert_equal expected_lines, @searcher_spec.
|
271
|
+
# assert_equal expected_lines, @searcher_spec.find_file_contents
|
272
272
|
# end
|
273
273
|
end
|
274
274
|
|
data/lib/find_files.rb
CHANGED
@@ -4,25 +4,29 @@
|
|
4
4
|
# encoding=utf-8
|
5
5
|
# version 2024-01-15
|
6
6
|
|
7
|
-
# Finds files matching a given pattern within specified directory paths
|
7
|
+
# Finds files matching a given pattern within specified directory paths while optionally excluding
|
8
|
+
# "." and ".." entries and directory names from the results.
|
8
9
|
#
|
9
|
-
# The function takes a pattern (filename or pattern with wildcards)
|
10
|
+
# The function takes a pattern (filename or pattern with wildcards), an array of paths, and an
|
11
|
+
# option to exclude directory entries and special entries "." and "..".
|
10
12
|
# It searches for files matching the pattern within each of the specified paths. Hidden files
|
11
|
-
# are
|
13
|
+
# are included in the search. The search can include subdirectories depending on the
|
12
14
|
# path specification (e.g., 'dir/**' for recursive search).
|
13
15
|
#
|
14
16
|
# Args:
|
15
17
|
# pattern (String): A filename or a pattern string with wildcards.
|
16
18
|
# paths (Array<String>): An array of directory paths where the search will be performed.
|
17
19
|
# Paths can include wildcards for recursive search.
|
20
|
+
# exclude_dirs (Boolean): If true, excludes "." and ".." and directory names from the results.
|
18
21
|
#
|
19
22
|
# Returns:
|
20
|
-
# Array<String>: A unique list of file paths that match the given pattern in the specified paths
|
23
|
+
# Array<String>: A unique list of file paths that match the given pattern in the specified paths,
|
24
|
+
# excluding directories if exclude_dirs is true.
|
21
25
|
#
|
22
26
|
# Example:
|
23
|
-
# find_files('version.rb', ['lib/**', 'spec'])
|
27
|
+
# find_files('version.rb', ['lib/**', 'spec'], true)
|
24
28
|
# # This might return file paths like ['lib/markdown_exec/version.rb', 'spec/version_spec.rb'].
|
25
|
-
def find_files(pattern, paths = ['', Dir.pwd])
|
29
|
+
def find_files(pattern, paths = ['', Dir.pwd], exclude_dirs: false)
|
26
30
|
matched_files = []
|
27
31
|
|
28
32
|
paths.each do |path_with_wildcard|
|
@@ -30,12 +34,51 @@ def find_files(pattern, paths = ['', Dir.pwd])
|
|
30
34
|
search_pattern = File.join(path_with_wildcard, pattern)
|
31
35
|
|
32
36
|
# Use Dir.glob with the File::FNM_DOTMATCH flag to include hidden files
|
33
|
-
|
37
|
+
files = Dir.glob(search_pattern, File::FNM_DOTMATCH)
|
38
|
+
|
39
|
+
# Optionally exclude "." and ".." and directory names
|
40
|
+
if exclude_dirs
|
41
|
+
files.reject! { |file| file.end_with?('/.', '/..') || File.directory?(file) }
|
42
|
+
end
|
43
|
+
|
44
|
+
matched_files += files
|
34
45
|
end
|
35
46
|
|
36
47
|
matched_files.uniq
|
37
48
|
end
|
38
49
|
|
50
|
+
# # Finds files matching a given pattern within specified directory paths.
|
51
|
+
# #
|
52
|
+
# # The function takes a pattern (filename or pattern with wildcards) and an array of paths.
|
53
|
+
# # It searches for files matching the pattern within each of the specified paths. Hidden files
|
54
|
+
# # are also included in the search. The search can include subdirectories depending on the
|
55
|
+
# # path specification (e.g., 'dir/**' for recursive search).
|
56
|
+
# #
|
57
|
+
# # Args:
|
58
|
+
# # pattern (String): A filename or a pattern string with wildcards.
|
59
|
+
# # paths (Array<String>): An array of directory paths where the search will be performed.
|
60
|
+
# # Paths can include wildcards for recursive search.
|
61
|
+
# #
|
62
|
+
# # Returns:
|
63
|
+
# # Array<String>: A unique list of file paths that match the given pattern in the specified paths.
|
64
|
+
# #
|
65
|
+
# # Example:
|
66
|
+
# # find_files('version.rb', ['lib/**', 'spec'])
|
67
|
+
# # # This might return file paths like ['lib/markdown_exec/version.rb', 'spec/version_spec.rb'].
|
68
|
+
# def find_files(pattern, paths = ['', Dir.pwd])
|
69
|
+
# matched_files = []
|
70
|
+
|
71
|
+
# paths.each do |path_with_wildcard|
|
72
|
+
# # Combine the path with the wildcard and the pattern
|
73
|
+
# search_pattern = File.join(path_with_wildcard, pattern)
|
74
|
+
|
75
|
+
# # Use Dir.glob with the File::FNM_DOTMATCH flag to include hidden files
|
76
|
+
# matched_files += Dir.glob(search_pattern, File::FNM_DOTMATCH)
|
77
|
+
# end
|
78
|
+
|
79
|
+
# matched_files.uniq
|
80
|
+
# end
|
81
|
+
|
39
82
|
return if $PROGRAM_NAME != __FILE__
|
40
83
|
|
41
84
|
# example CLI
|
data/lib/hash_delegator.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
|
4
4
|
# encoding=utf-8
|
5
5
|
|
6
|
-
require 'English'
|
7
6
|
require 'clipboard'
|
7
|
+
require 'English'
|
8
8
|
require 'fileutils'
|
9
9
|
require 'open3'
|
10
10
|
require 'optparse'
|
@@ -22,7 +22,6 @@ require_relative 'block_label'
|
|
22
22
|
require_relative 'block_types'
|
23
23
|
require_relative 'cached_nested_file_reader'
|
24
24
|
require_relative 'constants'
|
25
|
-
require_relative 'std_out_err_logger'
|
26
25
|
require_relative 'directory_searcher'
|
27
26
|
require_relative 'exceptions'
|
28
27
|
require_relative 'fcb'
|
@@ -32,6 +31,7 @@ require_relative 'hash'
|
|
32
31
|
require_relative 'link_history'
|
33
32
|
require_relative 'mdoc'
|
34
33
|
require_relative 'regexp'
|
34
|
+
require_relative 'std_out_err_logger'
|
35
35
|
require_relative 'string_util'
|
36
36
|
|
37
37
|
class String
|
@@ -365,6 +365,23 @@ module PathUtils
|
|
365
365
|
end
|
366
366
|
end
|
367
367
|
|
368
|
+
class BashCommentFormatter
|
369
|
+
# Formats a multi-line string into a format safe for use in Bash comments.
|
370
|
+
def self.format_comment(input_string)
|
371
|
+
return '# ' if input_string.nil?
|
372
|
+
return '# ' if input_string.empty?
|
373
|
+
|
374
|
+
formatted = input_string.split("\n").map do |line|
|
375
|
+
"# #{line.gsub('#', '\#')}"
|
376
|
+
end
|
377
|
+
formatted.join("\n")
|
378
|
+
end
|
379
|
+
# # fit oname in single bash comment
|
380
|
+
# def oname_for_bash_comment(oname)
|
381
|
+
# oname.gsub("\n", ' ~ ').gsub(/ +/, ' ')
|
382
|
+
# end
|
383
|
+
end
|
384
|
+
|
368
385
|
module MarkdownExec
|
369
386
|
class DebugHelper
|
370
387
|
# Class-level variable to store history of printed messages
|
@@ -1336,28 +1353,28 @@ module MarkdownExec
|
|
1336
1353
|
}
|
1337
1354
|
end
|
1338
1355
|
|
1339
|
-
# # Loads auto link block.
|
1340
|
-
# def load_auto_link_block(all_blocks, link_state, mdoc, block_source:)
|
1341
|
-
# block_name = @delegate_object[:document_load_link_block_name]
|
1342
|
-
# return unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
|
1356
|
+
# # Loads auto link block.
|
1357
|
+
# def load_auto_link_block(all_blocks, link_state, mdoc, block_source:)
|
1358
|
+
# block_name = @delegate_object[:document_load_link_block_name]
|
1359
|
+
# return unless block_name.present? && @most_recent_loaded_filename != @delegate_object[:filename]
|
1343
1360
|
|
1344
|
-
# block = HashDelegator.block_find(all_blocks, :oname, block_name)
|
1345
|
-
# return unless block
|
1361
|
+
# block = HashDelegator.block_find(all_blocks, :oname, block_name)
|
1362
|
+
# return unless block
|
1346
1363
|
|
1347
|
-
# if block.fetch(:shell, '') != BlockType::LINK
|
1348
|
-
# HashDelegator.error_handler('must be Link block type', { abort: true })
|
1364
|
+
# if block.fetch(:shell, '') != BlockType::LINK
|
1365
|
+
# HashDelegator.error_handler('must be Link block type', { abort: true })
|
1349
1366
|
|
1350
|
-
# else
|
1351
|
-
# # debounce_reset
|
1352
|
-
# push_link_history_and_trigger_load(
|
1353
|
-
# link_block_body: block.fetch(:body, ''),
|
1354
|
-
# mdoc: mdoc,
|
1355
|
-
# selected: block,
|
1356
|
-
# link_state: link_state,
|
1357
|
-
# block_source: block_source
|
1358
|
-
# )
|
1359
|
-
# end
|
1360
|
-
# end
|
1367
|
+
# else
|
1368
|
+
# # debounce_reset
|
1369
|
+
# push_link_history_and_trigger_load(
|
1370
|
+
# link_block_body: block.fetch(:body, ''),
|
1371
|
+
# mdoc: mdoc,
|
1372
|
+
# selected: block,
|
1373
|
+
# link_state: link_state,
|
1374
|
+
# block_source: block_source
|
1375
|
+
# )
|
1376
|
+
# end
|
1377
|
+
# end
|
1361
1378
|
|
1362
1379
|
# Loads auto blocks based on delegate object settings and updates if new filename is detected.
|
1363
1380
|
# Executes a specified block once per filename.
|
@@ -1754,7 +1771,7 @@ module MarkdownExec
|
|
1754
1771
|
# load key and values from link block into current environment
|
1755
1772
|
#
|
1756
1773
|
if link_block_data[LinkKeys::Vars]
|
1757
|
-
code_lines.push
|
1774
|
+
code_lines.push BashCommentFormatter.format_comment(selected[:oname])
|
1758
1775
|
(link_block_data[LinkKeys::Vars] || []).each do |(key, value)|
|
1759
1776
|
ENV[key] = value.to_s
|
1760
1777
|
code_lines.push(assign_key_value_in_bash(key, value))
|
@@ -1907,9 +1924,9 @@ module MarkdownExec
|
|
1907
1924
|
debounce_reset
|
1908
1925
|
link_state = LinkState.new
|
1909
1926
|
options_state = read_show_options_and_trigger_reuse(
|
1910
|
-
|
1911
|
-
|
1912
|
-
|
1927
|
+
selected: @dml_block_state.block,
|
1928
|
+
link_state: link_state
|
1929
|
+
)
|
1913
1930
|
|
1914
1931
|
@menu_base_options.merge!(options_state.options)
|
1915
1932
|
@delegate_object.merge!(options_state.options)
|
@@ -2103,15 +2120,25 @@ module MarkdownExec
|
|
2103
2120
|
|
2104
2121
|
# Presents a TTY prompt to select an option or exit, returns metadata including option and selected
|
2105
2122
|
def select_option_with_metadata(prompt_text, names, opts = {})
|
2123
|
+
|
2124
|
+
## configure to environment
|
2125
|
+
#
|
2126
|
+
unless opts[:select_page_height].positive?
|
2127
|
+
require 'io/console'
|
2128
|
+
opts[:per_page] = opts[:select_page_height] = [IO.console.winsize[0] - 3, 4].max
|
2129
|
+
end
|
2130
|
+
|
2106
2131
|
selection = @prompt.select(prompt_text,
|
2107
2132
|
names,
|
2108
2133
|
opts.merge(filter: true))
|
2109
|
-
|
2110
|
-
|
2111
|
-
|
2112
|
-
|
2113
|
-
|
2114
|
-
|
2134
|
+
item = names.find do |item|
|
2135
|
+
if item.instance_of?(String)
|
2136
|
+
item == selection
|
2137
|
+
else
|
2138
|
+
item[:dname] == selection
|
2139
|
+
end
|
2140
|
+
end
|
2141
|
+
item = { dname: item } if item.instance_of?(String)
|
2115
2142
|
unless item
|
2116
2143
|
HashDelegator.error_handler('select_option_with_metadata', error: 'menu item not found')
|
2117
2144
|
exit 1
|
@@ -2318,10 +2345,6 @@ module MarkdownExec
|
|
2318
2345
|
end
|
2319
2346
|
|
2320
2347
|
sph = @delegate_object[:select_page_height]
|
2321
|
-
unless sph.positive?
|
2322
|
-
require 'io/console'
|
2323
|
-
sph = [IO.console.winsize[0] - 3, 4].max
|
2324
|
-
end
|
2325
2348
|
selection_opts.merge!(per_page: sph)
|
2326
2349
|
|
2327
2350
|
selected_option = select_option_with_metadata(prompt_title, block_menu,
|
@@ -2387,9 +2410,9 @@ module MarkdownExec
|
|
2387
2410
|
clean_hash_recursively(value)
|
2388
2411
|
when Struct
|
2389
2412
|
struct_hash = value.to_h # Convert the Struct to a hash
|
2390
|
-
|
2413
|
+
clean_hash_recursively(struct_hash) # Clean the hash
|
2391
2414
|
# Return the cleaned hash instead of updating the Struct
|
2392
|
-
|
2415
|
+
|
2393
2416
|
else
|
2394
2417
|
value
|
2395
2418
|
end
|
@@ -2402,9 +2425,7 @@ module MarkdownExec
|
|
2402
2425
|
obj[key] = cleaned_value if value.is_a?(Hash) || value.is_a?(Struct)
|
2403
2426
|
end
|
2404
2427
|
|
2405
|
-
if obj.is_a?(Hash)
|
2406
|
-
obj.select! { |key, value| ![nil, '', [], {}, nil].include?(value) }
|
2407
|
-
end
|
2428
|
+
obj.reject! { |_key, value| [nil, '', [], {}, nil].include?(value) } if obj.is_a?(Hash)
|
2408
2429
|
|
2409
2430
|
obj
|
2410
2431
|
end
|
@@ -2438,7 +2459,42 @@ Bundler.require(:default)
|
|
2438
2459
|
require 'minitest/autorun'
|
2439
2460
|
require 'mocha/minitest'
|
2440
2461
|
|
2441
|
-
|
2462
|
+
class BashCommentFormatterTest < Minitest::Test
|
2463
|
+
# Test formatting a normal string without special characters
|
2464
|
+
def test_format_simple_string
|
2465
|
+
input = 'This is a simple comment.'
|
2466
|
+
expected = '# This is a simple comment.'
|
2467
|
+
assert_equal expected, BashCommentFormatter.format_comment(input)
|
2468
|
+
end
|
2469
|
+
|
2470
|
+
# Test formatting a string containing hash characters
|
2471
|
+
def test_format_string_with_hash
|
2472
|
+
input = 'This is a #comment with hash.'
|
2473
|
+
expected = '# This is a \\#comment with hash.'
|
2474
|
+
assert_equal expected, BashCommentFormatter.format_comment(input)
|
2475
|
+
end
|
2476
|
+
|
2477
|
+
# Test formatting an empty string
|
2478
|
+
def test_format_empty_string
|
2479
|
+
input = ''
|
2480
|
+
expected = '# '
|
2481
|
+
assert_equal expected, BashCommentFormatter.format_comment(input)
|
2482
|
+
end
|
2483
|
+
|
2484
|
+
# Test formatting a multi-line string
|
2485
|
+
def test_format_multi_line_string
|
2486
|
+
input = "This is the first line.\nThis is the second line."
|
2487
|
+
expected = "# This is the first line.\n# This is the second line."
|
2488
|
+
assert_equal expected, BashCommentFormatter.format_comment(input)
|
2489
|
+
end
|
2490
|
+
|
2491
|
+
# Test formatting strings with leading and trailing whitespace
|
2492
|
+
def test_format_whitespace
|
2493
|
+
input = ' This has leading and trailing spaces '
|
2494
|
+
expected = '# This has leading and trailing spaces '
|
2495
|
+
assert_equal expected, BashCommentFormatter.format_comment(input)
|
2496
|
+
end
|
2497
|
+
end
|
2442
2498
|
|
2443
2499
|
module MarkdownExec
|
2444
2500
|
class TestHashDelegator0 < Minitest::Test
|
@@ -3294,31 +3350,37 @@ module MarkdownExec
|
|
3294
3350
|
|
3295
3351
|
class PathUtilsTest < Minitest::Test
|
3296
3352
|
def test_absolute_path_returns_unchanged
|
3297
|
-
absolute_path =
|
3298
|
-
expression =
|
3353
|
+
absolute_path = '/usr/local/bin'
|
3354
|
+
expression = 'path/to/*/directory'
|
3299
3355
|
assert_equal absolute_path, PathUtils.resolve_path_or_substitute(absolute_path, expression)
|
3300
3356
|
end
|
3301
3357
|
|
3302
3358
|
def test_relative_path_gets_substituted
|
3303
|
-
relative_path =
|
3304
|
-
expression =
|
3305
|
-
expected_output =
|
3359
|
+
relative_path = 'my_folder'
|
3360
|
+
expression = 'path/to/*/directory'
|
3361
|
+
expected_output = 'path/to/my_folder/directory'
|
3306
3362
|
assert_equal expected_output, PathUtils.resolve_path_or_substitute(relative_path, expression)
|
3307
3363
|
end
|
3308
3364
|
|
3309
3365
|
def test_path_with_no_slash_substitutes_correctly
|
3310
|
-
relative_path =
|
3311
|
-
expression =
|
3312
|
-
expected_output =
|
3366
|
+
relative_path = 'data'
|
3367
|
+
expression = 'path/to/*/directory'
|
3368
|
+
expected_output = 'path/to/data/directory'
|
3313
3369
|
assert_equal expected_output, PathUtils.resolve_path_or_substitute(relative_path, expression)
|
3314
3370
|
end
|
3315
3371
|
|
3316
3372
|
def test_empty_path_substitution
|
3317
|
-
empty_path =
|
3318
|
-
expression =
|
3319
|
-
expected_output =
|
3373
|
+
empty_path = ''
|
3374
|
+
expression = 'path/to/*/directory'
|
3375
|
+
expected_output = 'path/to//directory'
|
3320
3376
|
assert_equal expected_output, PathUtils.resolve_path_or_substitute(empty_path, expression)
|
3321
3377
|
end
|
3322
|
-
end
|
3323
3378
|
|
3379
|
+
# Test formatting a string containing UTF-8 characters
|
3380
|
+
def test_format_utf8_characters
|
3381
|
+
input = 'Unicode test: ā, ö, 💻, and 🚀 are fun!'
|
3382
|
+
expected = '# Unicode test: ā, ö, 💻, and 🚀 are fun!'
|
3383
|
+
assert_equal expected, BashCommentFormatter.format_comment(input)
|
3384
|
+
end
|
3385
|
+
end
|
3324
3386
|
end # module MarkdownExec
|
data/lib/markdown_exec.rb
CHANGED
@@ -23,6 +23,7 @@ require_relative 'env'
|
|
23
23
|
require_relative 'exceptions'
|
24
24
|
require_relative 'fcb'
|
25
25
|
require_relative 'filter'
|
26
|
+
require_relative 'find_files'
|
26
27
|
require_relative 'fout'
|
27
28
|
require_relative 'hash_delegator'
|
28
29
|
require_relative 'input_sequencer'
|
@@ -102,6 +103,45 @@ end
|
|
102
103
|
module MarkdownExec
|
103
104
|
include Exceptions
|
104
105
|
|
106
|
+
class SearchResultsReport < DirectorySearcher
|
107
|
+
def directory_names(search_options, highlight_value)
|
108
|
+
matched_directories = find_directory_names
|
109
|
+
{
|
110
|
+
section_title: 'directory names',
|
111
|
+
data: matched_directories,
|
112
|
+
formatted_text: [{ content: AnsiFormatter.new(search_options).format_and_highlight_array(matched_directories, highlight: [highlight_value]) }]
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def file_contents(search_options, highlight_value)
|
117
|
+
matched_contents = find_file_contents.map.with_index do |(file, contents), index|
|
118
|
+
[file, contents.map { |detail| format('=%4.d: %s', detail.index, detail.line) }, index]
|
119
|
+
end
|
120
|
+
{
|
121
|
+
section_title: 'file contents',
|
122
|
+
data: matched_contents.map(&:first),
|
123
|
+
formatted_text: matched_contents.map do |(file, details, index)|
|
124
|
+
{ header: format('- %3.d: %s', index + 1, file),
|
125
|
+
content: AnsiFormatter.new(search_options).format_and_highlight_array(
|
126
|
+
details,
|
127
|
+
highlight: [highlight_value]
|
128
|
+
) }
|
129
|
+
end
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
def file_names(search_options, highlight_value)
|
134
|
+
matched_files = find_file_names
|
135
|
+
{
|
136
|
+
section_title: 'file names',
|
137
|
+
data: matched_files,
|
138
|
+
formatted_text: [{ content: AnsiFormatter.new(search_options).format_and_highlight_array(
|
139
|
+
matched_files, highlight: [highlight_value]
|
140
|
+
).join("\n") }]
|
141
|
+
}
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
105
145
|
##
|
106
146
|
#
|
107
147
|
# :reek:DuplicateMethodCall { allow_calls: ['block', 'item', 'lm', 'opts', 'option', '@options', 'required_blocks'] }
|
@@ -286,6 +326,8 @@ module MarkdownExec
|
|
286
326
|
@options[:path] = pos
|
287
327
|
elsif File.exist?(pos)
|
288
328
|
@options[:filename] = pos
|
329
|
+
elsif @options[:default_find_select_open]
|
330
|
+
find_value(pos, execute_chosen_found: true)
|
289
331
|
else
|
290
332
|
raise FileMissingError, pos, caller
|
291
333
|
end
|
@@ -303,6 +345,47 @@ module MarkdownExec
|
|
303
345
|
error_handler('finalize_cli_argument_processing')
|
304
346
|
end
|
305
347
|
|
348
|
+
# return { exit: true } to cause app to exit
|
349
|
+
def find_value(value, execute_chosen_found: false)
|
350
|
+
find_path = @options[:find_path].present? ? @options[:find_path] : @options[:path]
|
351
|
+
@fout.fout 'Searching in: ' \
|
352
|
+
"#{HashDelegator.new(@options).string_send_color(find_path,
|
353
|
+
:menu_chrome_color)}"
|
354
|
+
searcher = SearchResultsReport.new(value, [find_path])
|
355
|
+
file_names = searcher.file_names(options, value)
|
356
|
+
file_contents = searcher.file_contents(options, value)
|
357
|
+
directory_names = searcher.directory_names(options, value)
|
358
|
+
|
359
|
+
### search in file contents (block names, chrome, or text)
|
360
|
+
[file_contents,
|
361
|
+
directory_names,
|
362
|
+
file_names].each do |data|
|
363
|
+
@fout.fout "In #{data[:section_title]}" if data[:section_title]
|
364
|
+
next unless data[:formatted_text]
|
365
|
+
|
366
|
+
data[:formatted_text].each do |fi|
|
367
|
+
@fout.fout fi[:header] if fi[:header]
|
368
|
+
@fout.fout fi[:content] if fi[:content]
|
369
|
+
end
|
370
|
+
end
|
371
|
+
return { exit: true } unless execute_chosen_found
|
372
|
+
|
373
|
+
## pick a document to open
|
374
|
+
#
|
375
|
+
files = directory_names[:data].map do |dn|
|
376
|
+
find_files('*', [dn], exclude_dirs: true)
|
377
|
+
end.flatten(1)
|
378
|
+
choices = \
|
379
|
+
[{ disabled: '', name: "in #{file_names[:section_title]}".cyan }] \
|
380
|
+
+ file_names[:data] \
|
381
|
+
+ [{ disabled: '', name: "in #{directory_names[:section_title]}".cyan }] \
|
382
|
+
+ files \
|
383
|
+
+ [{ disabled: '', name: "in #{file_contents[:section_title]}".cyan }] \
|
384
|
+
+ file_contents[:data]
|
385
|
+
@options[:filename] = select_document_if_multiple(choices)
|
386
|
+
{ exit: false }
|
387
|
+
end
|
388
|
+
|
306
389
|
## Sets up the options and returns the parsed arguments
|
307
390
|
#
|
308
391
|
def initialize_and_parse_cli_options
|
@@ -344,35 +427,9 @@ module MarkdownExec
|
|
344
427
|
->(value) { tap_config value: value }
|
345
428
|
when 'exit'
|
346
429
|
->(_) { exit }
|
347
|
-
when 'find'
|
430
|
+
when 'find', 'open'
|
348
431
|
->(value) {
|
349
|
-
|
350
|
-
@fout.fout 'Searching in: ' \
|
351
|
-
"#{HashDelegator.new(@options).string_send_color(find_path,
|
352
|
-
:menu_chrome_color)}"
|
353
|
-
searcher = DirectorySearcher.new(value, [find_path])
|
354
|
-
|
355
|
-
@fout.fout 'In file contents'
|
356
|
-
hash = searcher.search_in_file_contents
|
357
|
-
hash.each.with_index do |(key, v2), i1|
|
358
|
-
@fout.fout format('- %3.d: %s', i1 + 1, key)
|
359
|
-
@fout.fout AnsiFormatter.new(options).format_and_highlight_array(
|
360
|
-
v2.map { |nl| format('=%4.d: %s', nl.index, nl.line) },
|
361
|
-
highlight: [value]
|
362
|
-
)
|
363
|
-
end
|
364
|
-
|
365
|
-
@fout.fout 'In directory names'
|
366
|
-
@fout.fout AnsiFormatter.new(options).format_and_highlight_array(
|
367
|
-
searcher.search_in_directory_names, highlight: [value]
|
368
|
-
)
|
369
|
-
|
370
|
-
@fout.fout 'In file names'
|
371
|
-
@fout.fout AnsiFormatter.new(options).format_and_highlight_array(
|
372
|
-
searcher.search_in_file_names, highlight: [value]
|
373
|
-
).join("\n")
|
374
|
-
|
375
|
-
exit
|
432
|
+
exit if find_value(value, execute_chosen_found: procname == 'open').fetch(:exit, false)
|
376
433
|
}
|
377
434
|
when 'help'
|
378
435
|
->(_) {
|
@@ -553,9 +610,7 @@ module MarkdownExec
|
|
553
610
|
end
|
554
611
|
|
555
612
|
def saved_name_split(name)
|
556
|
-
# rubocop:disable Layout/LineLength
|
557
613
|
mf = /#{@options[:saved_script_filename_prefix]}_(?<time>[0-9\-]+)_(?<file>.+)_,_(?<block>.+)\.sh/.match(name)
|
558
|
-
# rubocop:enable Layout/LineLength
|
559
614
|
return unless mf
|
560
615
|
|
561
616
|
@options[:block_name] = mf[:block]
|
@@ -578,7 +633,8 @@ module MarkdownExec
|
|
578
633
|
def select_option_or_exit(prompt_text, strings, opts = {})
|
579
634
|
result = @options.select_option_with_metadata(prompt_text, strings,
|
580
635
|
opts)
|
581
|
-
|
636
|
+
### 2024-04-20 what for?
|
637
|
+
# return unless result.fetch(:option, nil)
|
582
638
|
|
583
639
|
result[:selected]
|
584
640
|
end
|
data/lib/menu.src.yml
CHANGED
@@ -82,7 +82,7 @@
|
|
82
82
|
- :arg_name: BOOL
|
83
83
|
:default: true
|
84
84
|
:description: debounce_execution
|
85
|
-
:env_var:
|
85
|
+
:env_var: MDE_DEBOUNCE_EXECUTION
|
86
86
|
:opt_name: debounce_execution
|
87
87
|
:procname: val_as_bool
|
88
88
|
|
@@ -94,6 +94,13 @@
|
|
94
94
|
:procname: debug
|
95
95
|
:short_name: d
|
96
96
|
|
97
|
+
- :arg_name: BOOL
|
98
|
+
:default: true
|
99
|
+
:description: default_find_select_open
|
100
|
+
:env_var: MDE_DEFAULT_FIND_SELECT_OPEN
|
101
|
+
:opt_name: default_find_select_open
|
102
|
+
:procname: val_as_bool
|
103
|
+
|
97
104
|
- :default: "> "
|
98
105
|
:env_var: MDE_DISPLAY_LEVEL_XBASE_PREFIX
|
99
106
|
:opt_name: display_level_xbase_prefix
|
@@ -716,6 +723,13 @@
|
|
716
723
|
:opt_name: no_chrome
|
717
724
|
:procname: val_as_bool
|
718
725
|
|
726
|
+
- :arg_name: OPEN
|
727
|
+
:default: ''
|
728
|
+
:description: Find argument in documents, present list, and open user selection
|
729
|
+
:long_name: open
|
730
|
+
:procname: open
|
731
|
+
:short_name: o
|
732
|
+
|
719
733
|
- :default:
|
720
734
|
:description: Expression to match to start collecting lines
|
721
735
|
:env_var: MDE_OUTPUT_ASSIGNMENT_BEGIN
|
data/lib/menu.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# MDE - Markdown Executor (2.0.
|
1
|
+
# MDE - Markdown Executor (2.0.4)
|
2
2
|
---
|
3
3
|
- :description: Show current configuration values
|
4
4
|
:procname: show_config
|
@@ -69,7 +69,7 @@
|
|
69
69
|
- :arg_name: BOOL
|
70
70
|
:default: true
|
71
71
|
:description: debounce_execution
|
72
|
-
:env_var:
|
72
|
+
:env_var: MDE_DEBOUNCE_EXECUTION
|
73
73
|
:opt_name: debounce_execution
|
74
74
|
:procname: val_as_bool
|
75
75
|
- :arg_name: BOOL
|
@@ -79,6 +79,12 @@
|
|
79
79
|
:long_name: debug
|
80
80
|
:procname: debug
|
81
81
|
:short_name: d
|
82
|
+
- :arg_name: BOOL
|
83
|
+
:default: true
|
84
|
+
:description: default_find_select_open
|
85
|
+
:env_var: MDE_DEFAULT_FIND_SELECT_OPEN
|
86
|
+
:opt_name: default_find_select_open
|
87
|
+
:procname: val_as_bool
|
82
88
|
- :default: "> "
|
83
89
|
:env_var: MDE_DISPLAY_LEVEL_XBASE_PREFIX
|
84
90
|
:opt_name: display_level_xbase_prefix
|
@@ -600,6 +606,12 @@
|
|
600
606
|
:env_var: MDE_NO_CHROME
|
601
607
|
:opt_name: no_chrome
|
602
608
|
:procname: val_as_bool
|
609
|
+
- :arg_name: OPEN
|
610
|
+
:default: ''
|
611
|
+
:description: Find argument in documents, present list, and open user selection
|
612
|
+
:long_name: open
|
613
|
+
:procname: open
|
614
|
+
:short_name: o
|
603
615
|
- :default:
|
604
616
|
:description: Expression to match to start collecting lines
|
605
617
|
:env_var: MDE_OUTPUT_ASSIGNMENT_BEGIN
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: markdown_exec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fareed Stevenson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: clipboard
|