markdown_exec 2.8.2 → 2.8.4

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -0
  3. data/Gemfile.lock +1 -1
  4. data/Rakefile +33 -23
  5. data/bats/{block-types.bats → block-type-bash.bats} +0 -25
  6. data/bats/block-type-link.bats +9 -0
  7. data/bats/block-type-port.bats +16 -0
  8. data/bats/block-type-ux-allowed.bats +29 -0
  9. data/bats/block-type-ux-auto.bats +1 -1
  10. data/bats/block-type-ux-chained.bats +9 -0
  11. data/bats/block-type-ux-echo-hash.bats +14 -0
  12. data/bats/block-type-ux-echo.bats +20 -0
  13. data/bats/block-type-ux-exec.bats +1 -1
  14. data/bats/block-type-ux-hidden.bats +9 -0
  15. data/bats/block-type-ux-invalid.bats +8 -0
  16. data/bats/block-type-ux-preconditions.bats +8 -0
  17. data/bats/block-type-ux-readonly.bats +10 -0
  18. data/bats/block-type-ux-transform.bats +1 -1
  19. data/bats/block-type-vars.bats +3 -3
  20. data/bats/indented-block-type-vars.bats +9 -0
  21. data/bats/indented-multi-line-output.bats +9 -0
  22. data/bats/line-decor-dynamic.bats +8 -0
  23. data/bats/test_helper.bash +19 -2
  24. data/bats/variable-expansion-multiline.bats +8 -0
  25. data/bats/variable-expansion.bats +1 -1
  26. data/bin/tab_completion.sh +0 -5
  27. data/bin/tab_completion.sh.erb +0 -5
  28. data/docs/dev/block-type-ux-allowed.md +80 -0
  29. data/docs/dev/block-type-ux-chained.md +21 -0
  30. data/docs/dev/block-type-ux-echo-hash.md +72 -0
  31. data/docs/dev/block-type-ux-echo.md +21 -0
  32. data/docs/dev/block-type-ux-hidden.md +21 -0
  33. data/docs/dev/block-type-ux-invalid.md +5 -0
  34. data/docs/dev/block-type-ux-preconditions.md +9 -0
  35. data/docs/dev/block-type-ux-readonly.md +7 -0
  36. data/docs/dev/block-type-ux-require.md +8 -4
  37. data/docs/dev/indented-block-type-vars.md +6 -0
  38. data/docs/dev/indented-multi-line-output.md +11 -0
  39. data/docs/dev/line-decor-dynamic.md +10 -0
  40. data/docs/dev/variable-expansion-multiline.md +31 -0
  41. data/lib/ansi_formatter.rb +0 -1
  42. data/lib/ansi_string.rb +10 -1
  43. data/lib/array.rb +0 -1
  44. data/lib/array_util.rb +0 -1
  45. data/lib/block_label.rb +1 -1
  46. data/lib/cached_nested_file_reader.rb +1 -1
  47. data/lib/constants.rb +18 -0
  48. data/lib/directory_searcher.rb +1 -1
  49. data/lib/exceptions.rb +0 -1
  50. data/lib/fcb.rb +51 -8
  51. data/lib/filter.rb +4 -4
  52. data/lib/format_table.rb +1 -0
  53. data/lib/fout.rb +1 -1
  54. data/lib/hash.rb +0 -1
  55. data/lib/hash_delegator.rb +403 -200
  56. data/lib/link_history.rb +17 -17
  57. data/lib/logged_struct.rb +429 -0
  58. data/lib/markdown_exec/version.rb +1 -1
  59. data/lib/markdown_exec.rb +3 -3
  60. data/lib/mdoc.rb +5 -17
  61. data/lib/menu.src.yml +3 -1
  62. data/lib/menu.yml +1 -1
  63. data/lib/namer.rb +4 -5
  64. data/lib/null_result.rb +131 -0
  65. data/lib/object_present.rb +1 -1
  66. data/lib/option_value.rb +1 -1
  67. data/lib/resize_terminal.rb +1 -2
  68. data/lib/saved_assets.rb +1 -1
  69. data/lib/saved_files_matcher.rb +1 -1
  70. data/lib/shell_session.rb +439 -0
  71. data/lib/streams_out.rb +0 -1
  72. data/lib/string_util.rb +11 -1
  73. data/lib/success_result.rb +112 -0
  74. data/lib/text_analyzer.rb +1 -0
  75. data/lib/ww.rb +9 -7
  76. metadata +33 -3
@@ -0,0 +1,72 @@
1
+ / This automatic block sets multiple variables and displays the first variable.
2
+ ```ux :[document_ux_BASENAME]
3
+ default: :echo
4
+ echo:
5
+ BASENAME: "$(basename `pwd`)"
6
+ DOCUMENTS: "${BASENAME%%_*}"
7
+ OPERATION: "${BASENAME##*_}"
8
+ name: BASENAME
9
+ readonly: true
10
+ ```
11
+ / This block displays the second variable in the first block.
12
+ ```ux :[DOCUMENTS]
13
+ name: DOCUMENTS
14
+ readonly: true
15
+ ```
16
+ / This block displays the third variable in the first block.
17
+ ```ux :[OPERATION]
18
+ name: OPERATION
19
+ readonly: true
20
+ ```
21
+ / Multiple UX blocks to set many variables for a specific name.
22
+ ```ux
23
+ echo:
24
+ Species: Pongo tapanuliensis
25
+ Genus: Pongo
26
+ Family: Hominidae
27
+ Order: Primates
28
+ Class: Mammalia
29
+ Phylum: Chordata
30
+ Kingdom: Animalia
31
+ Domain: Eukaryota
32
+ Year_Discovered: 2017
33
+ menu_format: 'Load %{name}'
34
+ name: Tapanuli Orangutan
35
+ ```
36
+ ```ux
37
+ echo:
38
+ Species: Histiophryne psychedelica
39
+ Genus: Histiophryne
40
+ Family: Antennariidae
41
+ Order: Lophiiformes
42
+ Class: Actinopterygii
43
+ Phylum: Chordata
44
+ Kingdom: Animalia
45
+ Domain: Eukaryota
46
+ Year_Discovered: 2009
47
+ menu_format: 'Load %{name}'
48
+ name: Psychedelic Frogfish
49
+ ```
50
+ / Start a table to format the output of UX blocks
51
+ | Variable| Value
52
+ | -| -
53
+ / A read-only variable in a UX block in a table
54
+ ```ux
55
+ menu_format: '| %{name}| ${%{name}}'
56
+ name: Species
57
+ readonly: true
58
+ ```
59
+ / A table row displays one variable in a table
60
+ | Genus| ${Genus}
61
+ / An editable variable in a UX block in a table
62
+ ```ux
63
+ menu_format: '| %{name}| ${%{name}}'
64
+ name: Family
65
+ ```
66
+ @import bats-document-configuration.md
67
+ ```opts :(document_opts)
68
+ # menu_ux_row_format: '| %{name}| ${%{name}}'
69
+ screen_width: 64
70
+ table_center: false
71
+ ux_auto_load_force_default: true
72
+ ```
@@ -0,0 +1,21 @@
1
+ / This automatic block sets VAR and displays the current value in the menu.
2
+ ```ux :[document_ux_VAR]
3
+ default: :echo
4
+ echo: $(basename `pwd`)
5
+ name: VAR
6
+ ```
7
+ / This block is not visible. Execute to display the inherited lines for testing.
8
+ ```opts :(menu_with_inherited_lines)
9
+ menu_with_inherited_lines: true
10
+ ```
11
+ / This block is not visible. Execute to set a new value, displayed by the block above.
12
+ ```ux :(VAR_has_count)
13
+ echo: $(basename `pwd` | wc -c)
14
+ name: VAR
15
+ ```
16
+ / This block is visible. Execute to set a new value, displayed by the block above.
17
+ ```ux :[IAB_has_count]
18
+ echo: $VAR$VAR
19
+ name: IAB
20
+ ```
21
+ @import bats-document-configuration.md
@@ -0,0 +1,21 @@
1
+ / a UX block requires a shell block and another UX block
2
+ ``` :(shell)
3
+ ENTITY='Pongo tapanuliensis,Pongo'
4
+ ```
5
+ ```ux :[SPECIES] +(shell) +(GENUS)
6
+ echo: "${ENTITY%%,*}"
7
+ name: SPECIES
8
+ ```
9
+ / required ux block requires another
10
+ ```ux :(GENUS) +[NAME]
11
+ echo: "${ENTITY##*,}"
12
+ name: GENUS
13
+ readonly: true
14
+ ```
15
+ / executed in context of prior ux blocks, uses their values
16
+ ```ux :[NAME]
17
+ echo: "$SPECIES - $GENUS"
18
+ name: NAME
19
+ readonly: true
20
+ ```
21
+ @import bats-document-configuration.md
@@ -0,0 +1,5 @@
1
+ / automatic block is invalid YAML
2
+ ```ux :[document_ux_SPECIES]
3
+ invalid
4
+ ```
5
+ @import bats-document-configuration.md
@@ -0,0 +1,9 @@
1
+ / an automatic UX block that has a precondition that must be met before it is executed
2
+ ```ux :[document_ux_SPECIES]
3
+ default: :exec
4
+ exec: printf "$MISSING_VARIABLE"
5
+ name: SPECIES
6
+ preconditions:
7
+ - MISSING_VARIABLE
8
+ ```
9
+ @import bats-document-configuration.md
@@ -0,0 +1,7 @@
1
+ / This automatic block sets VAR and displays the current value in the menu.
2
+ ```ux :[document_ux_VAR]
3
+ default: Pongo tapanuliensis
4
+ name: SPECIES
5
+ readonly: true
6
+ ```
7
+ @import bats-document-configuration.md
@@ -4,25 +4,29 @@ ENTITY='Pongo tapanuliensis,Pongo'
4
4
  ```
5
5
  ```ux :[document_ux_SPECIES] +(shell) +[ux_GENUS]
6
6
  default: :exec
7
- exec: printf "${ENTITY%%,*}"
7
+ exec: echo "${ENTITY%%,*}"
8
8
  name: SPECIES
9
+ transform: :chomp
9
10
  ```
10
11
  / required ux block requires another
11
12
  ```ux :[ux_GENUS] +[ux_NAME]
12
13
  default: :exec
13
- exec: printf "${ENTITY##*,}"
14
+ exec: echo "${ENTITY##*,}"
14
15
  name: GENUS
16
+ transform: :chomp
15
17
  ```
16
18
  / executed in context of prior ux blocks, uses their initial values
17
19
  ```ux :[ux_NAME]
18
20
  default: :exec
19
- exec: printf "$SPECIES - $GENUS"
21
+ exec: echo "$SPECIES - $GENUS"
20
22
  name: NAME
23
+ transform: :chomp
21
24
  ```
22
25
  / executed after other ux blocks, uses their initial values
23
26
  ```ux :[document_ux_NAME2]
24
27
  default: :exec
25
- exec: printf "$NAME"
28
+ exec: echo "$NAME"
26
29
  name: NAME2
30
+ transform: :chomp
27
31
  ```
28
32
  @import bats-document-configuration.md
@@ -0,0 +1,6 @@
1
+ / All lines of an indented block must have equal indents.
2
+ ```vars
3
+ Species: Pongo tapanuliensis
4
+ Genus: Pongo
5
+ ```
6
+ @import bats-document-configuration.md
@@ -0,0 +1,11 @@
1
+ / Retain whitespace in output from shell blocks
2
+ ``` :[make-output]
3
+ echo 'Species'
4
+ echo -e " Genus\n Family\tOrder"
5
+ ```
6
+ @import bats-document-configuration.md
7
+ ```opts :(document_opts)
8
+ line_decor_pre:
9
+ - :color_method: :ansi_38_2_200_200_33__48_2_60_60_32__0
10
+ :pattern: '%([^_]{0,64})%'
11
+ ```
@@ -0,0 +1,10 @@
1
+ / Demonstrate dynamic color names
2
+ / line_decor_pre is performed before line_decor_main and line_decor_post
3
+ %Species%
4
+ @import bats-document-configuration.md
5
+ ```opts :(document_opts)
6
+ line_decor_pre:
7
+ # bold italicized bright yellow text on light yellow background
8
+ - :color_method: :ansi_1__3__38_2_200_200_33__48_2_60_60_32__22_23_0
9
+ :pattern: '%([^_]{0,64})%'
10
+ ```
@@ -0,0 +1,31 @@
1
+ / assign a multiline string
2
+ ```vars :(document_vars)
3
+ Genus2: |
4
+ Pongo
5
+ Pongo
6
+ ```
7
+ /
8
+ / display the variable
9
+ __UX block__:
10
+ ```ux
11
+ name: Genus2
12
+ readonly: true
13
+ ```
14
+ /
15
+ / Confirm the string contains a newline `0a`
16
+ __Command substitution__:
17
+ Genus2 hex: $(printf "$Genus2" | hexdump -C)
18
+ /
19
+ / output with substitution
20
+ __Command substitution__:
21
+ Genus2 text: $(printf "$Genus2")
22
+ /
23
+ / output with substitution
24
+ __Command substitution__:
25
+ $(ls -1 G*)
26
+ /
27
+ / output with expansion
28
+ __Variable expansion__:
29
+ Genus2 text: ${Genus2}
30
+ /
31
+ @import bats-document-configuration.md
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env ruby
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # encoding=utf-8
data/lib/ansi_string.rb CHANGED
@@ -14,6 +14,15 @@ class AnsiString < String
14
14
  def method_missing(method_name, *args, &block)
15
15
  if dynamic_color_method?(method_name)
16
16
  case method_name.to_s
17
+ when /^ansi_/
18
+ segments = $'.split('__')
19
+ codes = ''
20
+ segments[0..-2].each do |segment|
21
+ codes += "\033[#{segment.split('_').join(';')}m"
22
+ end
23
+ codes += to_s
24
+ codes += "\033[#{segments.last.split('_').join(';')}m"
25
+ self.class.new(codes)
17
26
  when /^fg_bg_rgb_/
18
27
  bytes = $'.split('_')
19
28
  fg_bg_rgb_color(bytes[0..2].join(';'), bytes[3..5].join(';'))
@@ -148,6 +157,6 @@ class AnsiString < String
148
157
  # @param method_name [Symbol] The name of the method being checked.
149
158
  # @return [Boolean] True if the method name matches a dynamic color method.
150
159
  def dynamic_color_method?(method_name)
151
- method_name.to_s =~ /^(fg_bg_rgb_|fg_bg_rgbh_|fg_rgb_|fg_rgbh_)/
160
+ method_name.to_s =~ /^(ansi_|fg_bg_rgb_|fg_bg_rgbh_|fg_rgb_|fg_rgbh_)/
152
161
  end
153
162
  end
data/lib/array.rb CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env ruby
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # encoding=utf-8
data/lib/array_util.rb CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env ruby
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # encoding=utf-8
data/lib/block_label.rb CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env -S bundle exec ruby
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # encoding=utf-8
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env -S bundle exec ruby
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # encoding=utf-8
data/lib/constants.rb CHANGED
@@ -103,6 +103,24 @@ end
103
103
  BlockSelection = Struct.new(:id)
104
104
  SelectedBlockMenuState = Struct.new(:block, :source, :state)
105
105
 
106
+ # user responses to prompts to choose
107
+ class SelectResponse
108
+ def initialize(value)
109
+ @value = value
110
+ end
111
+
112
+ def continue?
113
+ @value == :ok
114
+ end
115
+
116
+ def self.continue?(value)
117
+ !value.is_a?(SelectResponse) || value.continue?
118
+ end
119
+ end
120
+
121
+ SelectResponse::BACK = SelectResponse.new(:back)
122
+ SelectResponse::OK = SelectResponse.new(:ok)
123
+
106
124
  class TtyMenu
107
125
  ENABLE = nil
108
126
  DISABLE = ''
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env -S bundle exec ruby
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # encoding=utf-8
data/lib/exceptions.rb CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env ruby
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # encoding=utf-8
data/lib/fcb.rb CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env -S bundle exec ruby
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # encoding=utf-8
@@ -20,11 +20,13 @@ def parse_yaml_of_ux_block(
20
20
  OpenStruct.new(
21
21
  allowed: export['allowed'],
22
22
  default: export['default'],
23
+ echo: export['echo'],
23
24
  exec: export['exec'],
24
25
  menu_format: export['menu_format'] || menu_format,
25
26
  name: name,
26
27
  preconditions: export['preconditions'],
27
28
  prompt: export['prompt'] || prompt,
29
+ readonly: export['readonly'].nil? ? false : export['readonly'],
28
30
  transform: export['transform'],
29
31
  validate: export['validate'] || validate
30
32
  )
@@ -72,6 +74,19 @@ module MarkdownExec
72
74
  @attrs.delete(key)
73
75
  end
74
76
 
77
+ # Removes and returns the first matching name from dependencies collection
78
+ # Checks nickname, oname, pub_name and s2title
79
+ # 2024-08-04 match oname for long block names
80
+ # 2024-08-04 match nickname
81
+ # may not exist if block name is duplicated
82
+ def delete_matching_name!(dependencies)
83
+ dependencies.delete(@attrs[:dname]) ||
84
+ dependencies.delete(@attrs[:nickname]) ||
85
+ dependencies.delete(@attrs[:oname]) ||
86
+ dependencies.delete(@attrs.pub_name) ||
87
+ dependencies.delete(@attrs[:s2title])
88
+ end
89
+
75
90
  # Derives a title from the body of an FCB object.
76
91
  # @param fcb [Object] The FCB object whose title is to be derived.
77
92
  # @return [String] The derived title.
@@ -137,9 +152,10 @@ module MarkdownExec
137
152
 
138
153
  @attrs[:center] = table_center
139
154
  oname = @attrs[:oname] = format(export.menu_format, export.to_h)
155
+ @attrs[:readonly] = export.readonly
140
156
  else
141
- # triggered by an empty block
142
- raise "Invalid data type: #{data.inspect}"
157
+ # triggered by an empty or non-YAML block
158
+ return NullResult.new(message: 'Invalid YAML', data: data)
143
159
  end
144
160
  end
145
161
 
@@ -147,9 +163,9 @@ module MarkdownExec
147
163
  (yield oname, BLOCK_TYPE_COLOR_OPTIONS[@attrs[:type]]),
148
164
  @attrs[:indent]
149
165
  )
150
- end
151
166
 
152
- private
167
+ SuccessResult.instance
168
+ end
153
169
 
154
170
  # Formats multiline body content as a title string.
155
171
  # indents all but first line with two spaces
@@ -162,6 +178,24 @@ module MarkdownExec
162
178
  end.join("\n") << "\n"
163
179
  end
164
180
 
181
+ # :reek:ManualDispatch
182
+ # 2024-08-04 match nickname
183
+ def is_dependency_of?(dependency_names)
184
+ dependency_names.include?(@attrs[:dname]) ||
185
+ dependency_names.include?(@attrs[:nickname]) ||
186
+ dependency_names.include?(@attrs[:oname]) ||
187
+ dependency_names.include?(@attrs.pub_name) ||
188
+ dependency_names.include?(@attrs[:s2title])
189
+ end
190
+
191
+ def is_named?(name)
192
+ @attrs[:dname] == name ||
193
+ @attrs[:nickname] == name ||
194
+ @attrs[:oname] == name ||
195
+ @attrs.pub_name == name ||
196
+ @attrs[:s2title] == name
197
+ end
198
+
165
199
  # :reek:ManualDispatch
166
200
  def method_missing(method, *args, &block)
167
201
  method_name = method.to_s
@@ -180,7 +214,16 @@ module MarkdownExec
180
214
  raise err
181
215
  end
182
216
 
183
- public
217
+ def name_in_menu!(indented_multi_line)
218
+ # Indent has been extracted from the first line,
219
+ # remove indent from the remaining lines.
220
+ @attrs[:dname] =
221
+ if @attrs[:indent].empty?
222
+ indented_multi_line
223
+ else
224
+ indented_multi_line.gsub("\n#{@attrs[:indent]}", "\n")
225
+ end
226
+ end
184
227
 
185
228
  def respond_to_missing?(method_name, include_private = false)
186
229
  @attrs.key?(method_name.to_sym) || super
@@ -256,8 +299,8 @@ if $PROGRAM_NAME == __FILE__
256
299
  end
257
300
 
258
301
  def sort_hash_recursively(hash)
259
- hash.each_with_object({}) do |(k, v), new_hash|
260
- new_hash[k] = v.is_a?(Hash) ? sort_hash_recursively(v) : v
302
+ hash.transform_values do |v|
303
+ v.is_a?(Hash) ? sort_hash_recursively(v) : v
261
304
  end.sort.to_h
262
305
  end
263
306
 
data/lib/filter.rb CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env -S bundle exec ruby
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # encoding=utf-8
@@ -123,12 +123,12 @@ module MarkdownExec
123
123
  #
124
124
  def self.apply_other_filters(options, filters, fcb)
125
125
  name = fcb.oname
126
- shell = fcb.shell
127
126
  filters[:fcb_chrome] = fcb.fetch(:chrome, false)
128
127
  filters[:shell_default] = (fcb.type == BlockType::SHELL)
129
128
 
130
- if options[:block_disable_match].present? &&
131
- fcb.start_line =~ Regexp.new(options[:block_disable_match])
129
+ if fcb.readonly ||
130
+ (options[:block_disable_match].present? &&
131
+ fcb.start_line =~ Regexp.new(options[:block_disable_match]))
132
132
  fcb.disabled = TtyMenu::DISABLE
133
133
  end
134
134
  return unless name.present?
data/lib/format_table.rb CHANGED
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env -S bundle exec ruby
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'ostruct'
data/lib/fout.rb CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env -S bundle exec ruby
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # encoding=utf-8
data/lib/hash.rb CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env ruby
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # encoding=utf-8