markdown_exec 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -3,8 +3,17 @@
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rake/testtask'
5
5
  require 'erb'
6
+ # require 'rspec'
7
+ require 'rubocop'
6
8
  require 'yaml'
7
9
 
10
+ # begin
11
+ # require 'rspec/core/rake_task'
12
+ # RSpec::Core::RakeTask.new(:spec)
13
+ # rescue LoadError
14
+ # puts 'RSpec is required to run some tests.'
15
+ # end
16
+
8
17
  Rake::TestTask.new(:test) do |task|
9
18
  task.libs << 'test'
10
19
  task.libs << 'lib'
@@ -13,10 +22,15 @@ end
13
22
 
14
23
  require 'rubocop/rake_task'
15
24
 
25
+ require_relative 'lib/cli'
26
+ require_relative 'lib/markdown_exec/version'
16
27
  require_relative 'lib/shared'
17
28
  require_relative 'lib/tap'
18
29
 
19
- include Tap # rubocop:disable Style/MixinUsage
30
+ include CLI
31
+
32
+ include Tap
33
+ tap_config envvar: MarkdownExec::TAP_DEBUG
20
34
 
21
35
  RuboCop::RakeTask.new do |task|
22
36
  task.requires << 'rubocop-minitest'
@@ -27,15 +41,15 @@ task :rubocopminitest do
27
41
  `rubocop --require rubocop-minitest`
28
42
  end
29
43
 
30
- require_relative 'lib/markdown_exec/version'
31
-
32
44
  task default: %i[test reek rubocop rubocopminitest]
45
+ # task default: %i[spec test reek rubocop rubocopminitest]
33
46
 
34
47
  # task :default => :build
35
48
 
36
49
  desc 'gem build'
37
50
  task :build do
38
- Rake::Task['update_tab_completion'].execute
51
+ Rake::Task['update_menu_yml'].execute
52
+ Rake::Task['update_tab_completion'].execute # after updated menu is readable
39
53
  system "gem build #{MarkdownExec::GEM_NAME}.gemspec"
40
54
  end
41
55
 
@@ -66,15 +80,545 @@ end
66
80
 
67
81
  private
68
82
 
69
- BF = 'bin'
70
-
71
- # format for use in array in bash script
72
- # `opts=<%= mde_tab_completions %>`
83
+ # write menu.yml
73
84
  #
74
- def words_list(words)
75
- words.map do |word|
76
- %("#{word}")
77
- end.join ' '
85
+ desc 'update menu.yml'
86
+ task :update_menu_yml do
87
+ menu_options = [
88
+
89
+ ## priority options
90
+ #
91
+ {
92
+ arg_name: 'NAME',
93
+ compreply: false,
94
+ description: 'Name of block',
95
+ env_var: 'MDE_BLOCK_NAME',
96
+ long_name: 'block-name',
97
+ opt_name: 'block_name',
98
+ short_name: 'b',
99
+ procname: 'val_as_str'
100
+ },
101
+ {
102
+ arg_name: 'PATH',
103
+ default: '.',
104
+ description: 'Read configuration file',
105
+ long_name: 'config',
106
+ procname: 'path'
107
+ },
108
+ {
109
+ arg_name: 'BOOL',
110
+ default: false,
111
+ description: 'Debug output',
112
+ env_var: MarkdownExec::TAP_DEBUG,
113
+ long_name: 'debug',
114
+ short_name: 'd',
115
+ procname: 'debug'
116
+ },
117
+ {
118
+ arg_name: 'RELATIVE_PATH',
119
+ compreply: '.',
120
+ description: 'Name of document',
121
+ env_var: 'MDE_FILENAME',
122
+ long_name: 'filename',
123
+ opt_name: 'filename',
124
+ short_name: 'f',
125
+ procname: 'val_as_str'
126
+ },
127
+ {
128
+ description: 'App help',
129
+ long_name: 'help',
130
+ short_name: 'h',
131
+ procname: 'help'
132
+ },
133
+ {
134
+ arg_name: 'RELATIVE_PATH',
135
+ default: '.',
136
+ description: 'Path to documents',
137
+ env_var: 'MDE_PATH',
138
+ long_name: 'path',
139
+ opt_name: 'path',
140
+ short_name: 'p',
141
+ procname: 'val_as_str'
142
+ },
143
+ {
144
+ arg_name: 'BOOL',
145
+ default: true,
146
+ description: 'Pause for user to approve script',
147
+ env_var: 'MDE_USER_MUST_APPROVE',
148
+ long_name: 'user-must-approve',
149
+ opt_name: 'user_must_approve',
150
+ short_name: 'q',
151
+ procname: 'val_as_bool'
152
+ },
153
+ {
154
+ description: "Print the gem's version",
155
+ long_name: 'version',
156
+ short_name: 'v',
157
+ procname: 'version'
158
+ },
159
+ {
160
+ description: 'Exit app',
161
+ long_name: 'exit',
162
+ short_name: 'x',
163
+ procname: 'exit' # ->(_) { exit }
164
+ },
165
+ {
166
+ description: 'Show current configuration values',
167
+ short_name: '0',
168
+ procname: 'show_config'
169
+ },
170
+
171
+ ## commands
172
+ #
173
+ {
174
+ description: 'List blocks',
175
+ long_name: 'list-blocks',
176
+ opt_name: 'list_blocks',
177
+ procname: 'val_as_bool'
178
+ },
179
+ {
180
+ description: 'List default configuration as environment variables',
181
+ long_name: 'list-default-env',
182
+ opt_name: 'list_default_env'
183
+ },
184
+ {
185
+ description: 'List default configuration as YAML',
186
+ long_name: 'list-default-yaml',
187
+ opt_name: 'list_default_yaml'
188
+ },
189
+ {
190
+ description: 'List docs in current folder',
191
+ long_name: 'list-docs',
192
+ opt_name: 'list_docs',
193
+ procname: 'val_as_bool'
194
+ },
195
+ {
196
+ description: 'List recent saved output',
197
+ long_name: 'list-recent-output',
198
+ opt_name: 'list_recent_output',
199
+ procname: 'val_as_bool'
200
+ },
201
+ {
202
+ description: 'List recent saved scripts',
203
+ long_name: 'list-recent-scripts',
204
+ opt_name: 'list_recent_scripts',
205
+ procname: 'val_as_bool'
206
+ },
207
+ {
208
+ description: 'Select and execute a recently saved output',
209
+ long_name: 'select-recent-output',
210
+ opt_name: 'select_recent_output',
211
+ procname: 'val_as_bool'
212
+ },
213
+ {
214
+ description: 'Select and execute a recently saved script',
215
+ long_name: 'select-recent-script',
216
+ opt_name: 'select_recent_script',
217
+ procname: 'val_as_bool'
218
+ },
219
+ {
220
+ description: 'List tab completions',
221
+ long_name: 'tab-completions',
222
+ opt_name: 'tab_completions',
223
+ procname: 'val_as_bool'
224
+ },
225
+ {
226
+ description: 'Run most recently saved script',
227
+ long_name: 'run-last-script',
228
+ opt_name: 'run_last_script',
229
+ procname: 'val_as_bool'
230
+ },
231
+ {
232
+ description: 'Gem home folder',
233
+ long_name: 'pwd',
234
+ opt_name: 'pwd',
235
+ procname: 'val_as_bool'
236
+ },
237
+
238
+ ## secondary options
239
+ #
240
+ {
241
+ arg_name: "INT.#{DISPLAY_LEVEL_BASE}-#{DISPLAY_LEVEL_MAX}",
242
+ default: DISPLAY_LEVEL_DEFAULT,
243
+ description: "Output display level (#{DISPLAY_LEVEL_BASE} to #{DISPLAY_LEVEL_MAX} [data, +context, +info])",
244
+ env_var: 'MDE_DISPLAY_LEVEL',
245
+ long_name: 'display-level',
246
+ opt_name: 'display_level',
247
+ procname: 'val_as_int'
248
+ },
249
+ {
250
+ arg_name: 'INT.1-',
251
+ default: 32,
252
+ description: 'Max. items to return in list',
253
+ env_var: 'MDE_LIST_COUNT',
254
+ long_name: 'list-count',
255
+ opt_name: 'list_count',
256
+ procname: 'val_as_int'
257
+ },
258
+ {
259
+ arg_name: 'PREFIX',
260
+ default: MarkdownExec::BIN_NAME,
261
+ description: 'Name prefix for stdout files',
262
+ env_var: 'MDE_LOGGED_STDOUT_FILENAME_PREFIX',
263
+ # long_name: 'logged-stdout-filename-prefix',
264
+ opt_name: 'logged_stdout_filename_prefix',
265
+ procname: 'val_as_str'
266
+ },
267
+ {
268
+ arg_name: 'BOOL',
269
+ default: false,
270
+ description: 'Display document name in block selection menu',
271
+ env_var: 'MDE_MENU_BLOCKS_WITH_DOCNAME',
272
+ # long_name: 'menu-blocks-with-docname',
273
+ opt_name: 'menu_blocks_with_docname',
274
+ procname: 'val_as_bool'
275
+ },
276
+ {
277
+ arg_name: 'BOOL',
278
+ default: false,
279
+ description: 'Display headings (levels 1,2,3) in block selection menu',
280
+ env_var: 'MDE_MENU_BLOCKS_WITH_HEADINGS',
281
+ # long_name: 'menu-blocks-with-headings',
282
+ opt_name: 'menu_blocks_with_headings',
283
+ procname: 'val_as_bool'
284
+ },
285
+ {
286
+ arg_name: 'BOOL',
287
+ default: false,
288
+ description: 'Display summary for execution',
289
+ env_var: 'MDE_OUTPUT_EXECUTION_SUMMARY',
290
+ long_name: 'output-execution-summary',
291
+ opt_name: 'output_execution_summary',
292
+ procname: 'val_as_bool'
293
+ },
294
+ {
295
+ arg_name: 'BOOL',
296
+ default: false,
297
+ description: 'Display script prior to execution',
298
+ env_var: 'MDE_OUTPUT_SCRIPT',
299
+ long_name: 'output-script',
300
+ opt_name: 'output_script',
301
+ procname: 'val_as_bool'
302
+ },
303
+ {
304
+ arg_name: 'BOOL',
305
+ default: true,
306
+ description: 'Display standard output from execution',
307
+ env_var: 'MDE_OUTPUT_STDOUT',
308
+ long_name: 'output-stdout',
309
+ opt_name: 'output_stdout',
310
+ procname: 'val_as_bool'
311
+ },
312
+ {
313
+ arg_name: 'BOOL',
314
+ default: false,
315
+ description: 'Save executed script',
316
+ env_var: 'MDE_SAVE_EXECUTED_SCRIPT',
317
+ long_name: 'save-executed-script',
318
+ opt_name: 'save_executed_script',
319
+ procname: 'val_as_bool'
320
+ },
321
+ {
322
+ arg_name: 'BOOL',
323
+ default: false,
324
+ description: 'Save standard output of the executed script',
325
+ env_var: 'MDE_SAVE_EXECUTION_OUTPUT',
326
+ long_name: 'save-execution-output',
327
+ opt_name: 'save_execution_output',
328
+ procname: 'val_as_bool'
329
+ },
330
+ {
331
+ arg_name: 'INT',
332
+ default: 0o755,
333
+ description: 'chmod for saved scripts',
334
+ env_var: 'MDE_SAVED_SCRIPT_CHMOD',
335
+ # long_name: 'saved-script-chmod',
336
+ opt_name: 'saved_script_chmod',
337
+ procname: 'val_as_int'
338
+ },
339
+ {
340
+ arg_name: 'PREFIX',
341
+ default: MarkdownExec::BIN_NAME,
342
+ description: 'Name prefix for saved scripts',
343
+ env_var: 'MDE_SAVED_SCRIPT_FILENAME_PREFIX',
344
+ # long_name: 'saved-script-filename-prefix',
345
+ opt_name: 'saved_script_filename_prefix',
346
+ procname: 'val_as_str'
347
+ },
348
+ {
349
+ arg_name: 'RELATIVE_PATH',
350
+ default: 'logs',
351
+ description: 'Saved script folder',
352
+ env_var: 'MDE_SAVED_SCRIPT_FOLDER',
353
+ long_name: 'saved-script-folder',
354
+ opt_name: 'saved_script_folder',
355
+ procname: 'val_as_str'
356
+ },
357
+ {
358
+ arg_name: 'GLOB',
359
+ default: 'mde_*.sh',
360
+ description: 'Glob matching saved scripts',
361
+ env_var: 'MDE_SAVED_SCRIPT_GLOB',
362
+ # long_name: 'saved-script-glob',
363
+ opt_name: 'saved_script_glob',
364
+ procname: 'val_as_str'
365
+ },
366
+ {
367
+ arg_name: 'RELATIVE_PATH',
368
+ default: 'logs',
369
+ description: 'Saved stdout folder',
370
+ env_var: 'MDE_SAVED_STDOUT_FOLDER',
371
+ long_name: 'saved-stdout-folder',
372
+ opt_name: 'saved_stdout_folder',
373
+ procname: 'val_as_str'
374
+ },
375
+ {
376
+ arg_name: 'GLOB',
377
+ default: 'mde_*.out.txt',
378
+ description: 'Glob matching saved outputs',
379
+ env_var: 'MDE_SAVED_STDOUT_GLOB',
380
+ # long_name: 'saved-stdout-glob',
381
+ opt_name: 'saved_stdout_glob',
382
+ procname: 'val_as_str'
383
+ },
384
+
385
+ {
386
+ default: '^[\(\[].*[\)\]]$',
387
+ description: 'Pattern for blocks to hide from user-selection',
388
+ env_var: 'MDE_BLOCK_NAME_HIDDEN_MATCH',
389
+ opt_name: 'block_name_hidden_match',
390
+ procname: 'val_as_str'
391
+ },
392
+ {
393
+ default: ':(?<title>\S+)( |$)',
394
+ env_var: 'MDE_BLOCK_NAME_MATCH',
395
+ opt_name: 'block_name_match',
396
+ procname: 'val_as_str'
397
+ },
398
+ {
399
+ default: '%\([^\)]+\)',
400
+ env_var: 'MDE_BLOCK_CALLS_SCAN',
401
+ opt_name: 'block_calls_scan',
402
+ procname: 'val_as_str'
403
+ },
404
+ {
405
+ default: '\+\S+',
406
+ env_var: 'MDE_BLOCK_REQUIRED_SCAN',
407
+ opt_name: 'block_required_scan',
408
+ procname: 'val_as_str'
409
+ },
410
+ {
411
+ default: '<(?<full>(?<type>\$)?(?<name>[A-Za-z]\S*))',
412
+ env_var: 'MDE_BLOCK_STDIN_SCAN',
413
+ opt_name: 'block_stdin_scan',
414
+ procname: 'val_as_str'
415
+ },
416
+ {
417
+ default: '>(?<full>(?<type>\$)?(?<name>[A-Za-z]\S*))',
418
+ env_var: 'MDE_BLOCK_STDOUT_SCAN',
419
+ opt_name: 'block_stdout_scan',
420
+ procname: 'val_as_str'
421
+ },
422
+ {
423
+ default: '> ',
424
+ env_var: 'MDE_DISPLAY_LEVEL_XBASE_PREFIX',
425
+ opt_name: 'display_level_xbase_prefix',
426
+ procname: 'val_as_str'
427
+ },
428
+ {
429
+ default: '^`{3,}',
430
+ env_var: 'MDE_FENCED_START_AND_END_MATCH',
431
+ opt_name: 'fenced_start_and_end_match',
432
+ procname: 'val_as_str'
433
+ },
434
+ {
435
+ default: '^`{3,}(?<shell>[^`\s]*) *(?<name>.*)$',
436
+ env_var: 'MDE_FENCED_START_EX_MATCH',
437
+ opt_name: 'fenced_start_ex_match',
438
+ procname: 'val_as_str'
439
+ },
440
+ {
441
+ default: '^# *(?<name>[^#]*?) *$',
442
+ env_var: 'MDE_HEADING1_MATCH',
443
+ opt_name: 'heading1_match',
444
+ procname: 'val_as_str'
445
+ },
446
+ {
447
+ default: '^## *(?<name>[^#]*?) *$',
448
+ env_var: 'MDE_HEADING2_MATCH',
449
+ opt_name: 'heading2_match',
450
+ procname: 'val_as_str'
451
+ },
452
+ {
453
+ default: '^### *(?<name>.+?) *$',
454
+ env_var: 'MDE_HEADING3_MATCH',
455
+ opt_name: 'heading3_match',
456
+ procname: 'val_as_str'
457
+ },
458
+ {
459
+ default: '*.[Mm][Dd]',
460
+ env_var: 'MDE_MD_FILENAME_GLOB',
461
+ opt_name: 'md_filename_glob',
462
+ procname: 'val_as_str'
463
+ },
464
+ {
465
+ default: '.+\\.md',
466
+ env_var: 'MDE_MD_FILENAME_MATCH',
467
+ opt_name: 'md_filename_match',
468
+ procname: 'val_as_str'
469
+ },
470
+ {
471
+ default: '-:= %s =:-',
472
+ description: 'format for menu dividers and demarcations',
473
+ env_var: 'MDE_MENU_DIVIDER_FORMAT',
474
+ opt_name: 'menu_divider_format',
475
+ procname: 'val_as_str'
476
+ },
477
+ {
478
+ default: 'magenta',
479
+ description: 'Color of menu divider',
480
+ env_var: 'MDE_MENU_DIVIDER_COLOR',
481
+ opt_name: 'menu_divider_color',
482
+ procname: 'val_as_str'
483
+ },
484
+ {
485
+ default: '^::: +(?<name>.+?)$',
486
+ description: 'Pattern for topics/dividers in block selection menu',
487
+ env_var: 'MDE_MENU_DIVIDER_MATCH',
488
+ opt_name: 'menu_divider_match',
489
+ procname: 'val_as_str'
490
+ },
491
+ {
492
+ default: '>',
493
+ description: 'Symbol before each divider',
494
+ env_var: 'MDE_MENU_DIVIDER_SYMBOL',
495
+ opt_name: 'menu_divider_symbol',
496
+ procname: 'val_as_str'
497
+ },
498
+ {
499
+ default: '~~~',
500
+ description: 'closing demarcations for menu',
501
+ env_var: 'MDE_MENU_FINAL_DIVIDER',
502
+ opt_name: 'menu_final_divider',
503
+ procname: 'val_as_str'
504
+ },
505
+ {
506
+ default: '',
507
+ description: 'opening demarcation for menu',
508
+ env_var: 'MDE_MENU_INITIAL_DIVIDER',
509
+ opt_name: 'menu_initial_divider',
510
+ procname: 'val_as_str'
511
+ },
512
+ {
513
+ description: 'Options for viewing saved output file',
514
+ env_var: 'MDE_OUTPUT_VIEWER_OPTIONS',
515
+ opt_name: 'output_viewer_options',
516
+ procname: 'val_as_str'
517
+ },
518
+ {
519
+ default: 36,
520
+ description: 'Maximum # of rows in select list',
521
+ env_var: 'MDE_SELECT_PAGE_HEIGHT',
522
+ opt_name: 'select_page_height',
523
+ procname: 'val_as_int'
524
+ },
525
+ {
526
+ default: '#!/usr/bin/env',
527
+ description: 'Shebang for saved scripts',
528
+ env_var: 'MDE_SHEBANG',
529
+ opt_name: 'shebang',
530
+ procname: 'val_as_str'
531
+ },
532
+ {
533
+ default: 'bash',
534
+ description: 'Shell for launched scripts',
535
+ env_var: 'MDE_SHELL',
536
+ opt_name: 'shell',
537
+ procname: 'val_as_str'
538
+ },
539
+ {
540
+ default: 'Process?',
541
+ description: 'Prompt to approve a block',
542
+ env_var: 'MDE_PROMPT_APPROVE_BLOCK',
543
+ opt_name: 'prompt_approve_block',
544
+ procname: 'val_as_str'
545
+ },
546
+ {
547
+ default: 'Choose a block:',
548
+ description: 'Prompt to select a block',
549
+ env_var: 'MDE_PROMPT_SELECT_BLOCK',
550
+ opt_name: 'prompt_select_block',
551
+ procname: 'val_as_str'
552
+ },
553
+ {
554
+ default: 'Choose a file:',
555
+ description: 'Prompt to select a markdown document',
556
+ env_var: 'MDE_PROMPT_SELECT_MD',
557
+ opt_name: 'prompt_select_md',
558
+ procname: 'val_as_str'
559
+ },
560
+ {
561
+ default: 'Choose a file:',
562
+ description: 'Prompt to select a saved file',
563
+ env_var: 'MDE_PROMPT_SELECT_OUTPUT',
564
+ opt_name: 'prompt_select_output',
565
+ procname: 'val_as_str'
566
+ },
567
+ {
568
+ default: 'Copy script to clipboard',
569
+ description: 'Prompt to copy script to clipboard',
570
+ env_var: 'MDE_PROMPT_SCRIPT_TO_CLIPBOARD',
571
+ opt_name: 'prompt_script_to_clipboard',
572
+ procname: 'val_as_str'
573
+ },
574
+ {
575
+ default: 'Save script',
576
+ description: 'Prompt to save script',
577
+ env_var: 'MDE_PROMPT_SAVE_SCRIPT',
578
+ opt_name: 'prompt_save_script',
579
+ procname: 'val_as_str'
580
+ },
581
+ {
582
+ default: 'No',
583
+ description: 'Prompt for no',
584
+ env_var: 'MDE_PROMPT_NO',
585
+ opt_name: 'prompt_no',
586
+ procname: 'val_as_str'
587
+ },
588
+ {
589
+ default: 'Yes',
590
+ description: 'Prompt for yes',
591
+ env_var: 'MDE_PROMPT_YES',
592
+ opt_name: 'prompt_yes',
593
+ procname: 'val_as_str'
594
+ },
595
+ {
596
+ default: ' #=#=#',
597
+ description: 'Output divider',
598
+ env_var: 'MDE_OUTPUT_DIVIDER',
599
+ opt_name: 'output_divider',
600
+ procname: 'val_as_str'
601
+ },
602
+ {
603
+ default: 'yellow',
604
+ description: 'Color of output divider',
605
+ env_var: 'MDE_OUTPUT_DIVIDER_COLOR',
606
+ opt_name: 'output_divider_color',
607
+ procname: 'val_as_str'
608
+ # },
609
+ # {
610
+ # default: '',
611
+ # description: '',
612
+ # env_var: 'MDE_PROMPT_',
613
+ # opt_name: 'prompt_',
614
+ # procname: 'val_as_str'
615
+ }
616
+ ]
617
+
618
+ File.write(MENU_YML,
619
+ "# #{MarkdownExec::APP_NAME} - #{MarkdownExec::APP_DESC} (#{MarkdownExec::VERSION})\n" +
620
+ menu_options.to_yaml)
621
+ puts `stat #{MENU_YML}`
78
622
  end
79
623
 
80
624
  # write tab_completion.sh with erb
@@ -83,14 +627,14 @@ def update_tab_completion(target)
83
627
  words = `#{File.join BF, MarkdownExec::BIN_NAME} --tab-completions`.split("\n")
84
628
  mde_tab_completions = "(#{words_list(words)})"
85
629
  mde_help = `#{File.join BF, MarkdownExec::BIN_NAME} --help`.split("\n")
86
- menu_export_yaml = `#{File.join BF, MarkdownExec::BIN_NAME} --menu-export`
87
630
 
88
- svhs = YAML.load menu_export_yaml # rubocop:disable Security/YAMLLoad
631
+ svhs = YAML.load File.open(MENU_YML)
89
632
  svhs.each do |svh|
90
- svh[:compreply] = value_for_cli(svh[:default]) if svh[:compreply].nil?
91
- end.tap_inspect name: :svhs, format: :yaml
633
+ svh[:compreply] = CLI::value_for_cli(svh[:default]) if svh[:compreply].nil?
634
+ end.tap_inspect name: :svhs, type: :yaml
92
635
 
93
- File.write target, ERB.new(File.read(File.join(BF, 'tab_completion.sh.erb'))).result(binding)
636
+ File.write target, ERB.new(File.read(filespec = File.join(BF, 'tab_completion.sh.erb'))).result(binding)
637
+ puts `stat #{filespec}`
94
638
  end
95
639
 
96
640
  desc 'update tab_completion.sh'
@@ -98,9 +642,18 @@ task :update_tab_completion do
98
642
  update_tab_completion File.join(BF, 'tab_completion.sh')
99
643
  end
100
644
 
101
- desc 'update tab_completion.sh'
645
+ desc 'update installed tab_completion.sh'
102
646
  task :update_installed_tab_completion do
103
647
  update_tab_completion(fs = File.join(`mde --pwd`.chomp, BF, 'tab_completion.sh'))
104
648
 
105
649
  puts `cat #{fs}` ###
106
650
  end
651
+
652
+ # format for use in array in bash script
653
+ # `opts=<%= mde_tab_completions %>`
654
+ #
655
+ def words_list(words)
656
+ words.map do |word|
657
+ %("#{word}")
658
+ end.join ' '
659
+ end