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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5a409e4d991db71ebae3bf9cfa6e7fcad695b6f5e1ffc017cffddc0ce168497
4
- data.tar.gz: 11e5a9c57f38a06a328310a0d368d9c136a959f1c75260e916cb9bd35706cda6
3
+ metadata.gz: eadeecd7019d53202aabe57d9486ee616826e6b5f42fce0fa24f8e377c1b50e5
4
+ data.tar.gz: cde007bddd4821263045eeba415cc1e2f42591d03294fc678c4093384373146b
5
5
  SHA512:
6
- metadata.gz: ac29e181ea9a2b6fbc081d7dc13288fed6990c4a215d3d9b0a25e499cfefe63346c1f648988495537c0147f954c9ddf4c76ee110a288d9a3dc1e821b47525282
7
- data.tar.gz: 992e6fa7a4438c5b580ad6b026ed351109b9b818106f647fc9c5234165abdd07bc729ff34a4bec6d0a678200a5de7c6bbbbceee2b395964a599a95622a8de06e
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
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.4] - 2024-04-22
4
+
5
+ ### Added
6
+
7
+ - Option to match and open directories and files.
8
+
3
9
  ## [2.0.3] - 2024-04-15
4
10
 
5
11
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- markdown_exec (2.0.3.2)
4
+ markdown_exec (2.0.4)
5
5
  clipboard (~> 1.3.6)
6
6
  open3 (~> 0.1.1)
7
7
  optparse (~> 0.1.1)
@@ -13,7 +13,7 @@ __filedirs_all()
13
13
  }
14
14
 
15
15
  _mde_echo_version() {
16
- echo "2.0.3.2"
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-18 00:24:36 UTC"
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
  ```
@@ -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 search_in_directory_names
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 search_in_file_names
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 search_in_file_contents
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 search_in_file_contents
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 search_in_directory_names method
223
- def test_search_in_directory_names
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.search_in_directory_names
225
+ assert_equal [], @searcher.find_directory_names
226
226
  end
227
227
 
228
- # Test search_in_file_names method
229
- def test_search_in_file_names
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.search_in_file_names
231
+ assert_equal [], @searcher.find_file_names
232
232
  end
233
233
 
234
- # Test search_in_file_contents method
235
- def test_search_in_file_contents
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.search_in_file_contents
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 search_in_directory_names method for 'spec'
253
- def test_search_in_directory_names_for_spec
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.search_in_directory_names
256
+ assert_equal expected_dirs, @searcher_spec.find_directory_names
257
257
  end
258
258
 
259
- # Test search_in_file_names method for 'spec'
260
- def test_search_in_file_names_for_spec
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.search_in_file_names
264
+ assert_equal expected_files, @searcher_spec.find_file_names
265
265
  end
266
266
 
267
- # # Test search_in_file_contents method for 'spec'
268
- # def test_search_in_file_contents_for_spec
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.search_in_file_contents
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) and an array of paths.
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 also included in the search. The search can include subdirectories depending on the
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
- matched_files += Dir.glob(search_pattern, File::FNM_DOTMATCH)
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
@@ -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 "# #{selected[:oname]}"
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
- selected: @dml_block_state.block,
1911
- link_state: link_state
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
- item = if names.first.instance_of?(String)
2111
- { dname: selection }
2112
- else
2113
- names.find { |item| item[:dname] == selection }
2114
- end
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
- cleaned_hash = clean_hash_recursively(struct_hash) # Clean the hash
2413
+ clean_hash_recursively(struct_hash) # Clean the hash
2391
2414
  # Return the cleaned hash instead of updating the Struct
2392
- return cleaned_hash
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
- require_relative 'std_out_err_logger'
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 = "/usr/local/bin"
3298
- expression = "path/to/*/directory"
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 = "my_folder"
3304
- expression = "path/to/*/directory"
3305
- expected_output = "path/to/my_folder/directory"
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 = "data"
3311
- expression = "path/to/*/directory"
3312
- expected_output = "path/to/data/directory"
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 = "path/to/*/directory"
3319
- expected_output = "path/to//directory"
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
@@ -7,5 +7,5 @@ module MarkdownExec
7
7
  BIN_NAME = 'mde'
8
8
  GEM_NAME = 'markdown_exec'
9
9
  TAP_DEBUG = 'MDE_DEBUG'
10
- VERSION = '2.0.3.2'
10
+ VERSION = '2.0.4'
11
11
  end
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
- find_path = @options[:find_path].present? ? @options[:find_path] : @options[:path]
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
- return unless result.fetch(:option, nil)
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: MDE_debounce_execution
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.3.2)
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: MDE_debounce_execution
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.3.2
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-18 00:00:00.000000000 Z
11
+ date: 2024-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clipboard