markdown_exec 3.5.1 → 3.5.2

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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/.ai-agent-instructions +54 -0
  3. data/.cursorrules +198 -0
  4. data/.rubocop.wide.yml +5 -0
  5. data/.rubocop.yml +7 -2
  6. data/CHANGELOG.md +12 -1
  7. data/Gemfile.lock +1 -1
  8. data/Rakefile +2 -0
  9. data/ai-principles.md +516 -0
  10. data/architecture-decisions.md +190 -0
  11. data/bats/block-hide.bats +1 -1
  12. data/bats/block-type-bash.bats +5 -5
  13. data/bats/block-type-link.bats +1 -1
  14. data/bats/block-type-opts.bats +3 -3
  15. data/bats/block-type-port.bats +2 -2
  16. data/bats/block-type-shell-require-ux.bats +2 -2
  17. data/bats/block-type-ux-allowed.bats +4 -4
  18. data/bats/block-type-ux-auto.bats +1 -1
  19. data/bats/block-type-ux-chained.bats +1 -1
  20. data/bats/block-type-ux-default.bats +1 -1
  21. data/bats/block-type-ux-echo-hash-transform.bats +1 -1
  22. data/bats/block-type-ux-echo-hash.bats +2 -2
  23. data/bats/block-type-ux-echo.bats +3 -3
  24. data/bats/block-type-ux-exec-hash-transform.bats +1 -1
  25. data/bats/block-type-ux-exec-hash.bats +2 -2
  26. data/bats/block-type-ux-exec.bats +1 -1
  27. data/bats/block-type-ux-force.bats +1 -1
  28. data/bats/block-type-ux-formats.bats +1 -1
  29. data/bats/block-type-ux-hidden.bats +1 -1
  30. data/bats/block-type-ux-invalid.bats +1 -1
  31. data/bats/block-type-ux-readonly.bats +1 -1
  32. data/bats/block-type-ux-require-chained.bats +2 -2
  33. data/bats/block-type-ux-require-context.bats +2 -2
  34. data/bats/block-type-ux-require.bats +2 -2
  35. data/bats/block-type-ux-required-variables.bats +1 -1
  36. data/bats/block-type-ux-row-format.bats +1 -1
  37. data/bats/block-type-ux-sources.bats +4 -4
  38. data/bats/block-type-ux-transform.bats +1 -1
  39. data/bats/block-type-vars.bats +3 -3
  40. data/bats/border.bats +1 -1
  41. data/bats/cli.bats +11 -11
  42. data/bats/command-substitution-options.bats +2 -2
  43. data/bats/command-substitution.bats +1 -1
  44. data/bats/document-shell.bats +1 -1
  45. data/bats/history.bats +5 -5
  46. data/bats/import-conflict.bats +1 -1
  47. data/bats/import-directive-line-continuation.bats +1 -1
  48. data/bats/import-directive-parameter-symbols.bats +1 -1
  49. data/bats/import-duplicates.bats +6 -6
  50. data/bats/import-parameter-symbols.bats +1 -1
  51. data/bats/import-with-text-substitution.bats +1 -1
  52. data/bats/import.bats +3 -3
  53. data/bats/indented-block-type-vars.bats +1 -1
  54. data/bats/indented-multi-line-output.bats +1 -1
  55. data/bats/line-decor-dynamic.bats +1 -1
  56. data/bats/line-wrapping.bats +1 -1
  57. data/bats/load-vars-state-demo.bats +4 -4
  58. data/bats/markup.bats +4 -4
  59. data/bats/mde.bats +4 -4
  60. data/bats/option-expansion.bats +1 -1
  61. data/bats/options-collapse.bats +4 -4
  62. data/bats/options.bats +47 -17
  63. data/bats/plain.bats +1 -1
  64. data/bats/publish.bats +2 -2
  65. data/bats/table-column-truncate.bats +1 -1
  66. data/bats/table.bats +2 -2
  67. data/bats/variable-expansion-multiline.bats +1 -1
  68. data/bats/variable-expansion.bats +6 -6
  69. data/conversation-template.md +611 -0
  70. data/docs/block-execution-modes.md +177 -0
  71. data/docs/block-filtering.md +252 -0
  72. data/docs/block-naming-patterns.md +210 -0
  73. data/docs/block-scanning-patterns.md +248 -0
  74. data/docs/cli-reference.md +370 -0
  75. data/docs/dev/block-hide.md +1 -1
  76. data/docs/dev/block-type-ux-transform.md +5 -4
  77. data/docs/dev/print_bytes.md +3 -0
  78. data/docs/dev/shebang.md +6 -0
  79. data/docs/docker-testing.md +5 -0
  80. data/docs/execution-control.md +384 -0
  81. data/docs/getting-started.md +209 -0
  82. data/docs/import-options.md +391 -0
  83. data/docs/tab-completion.md +7 -0
  84. data/docs/ux-blocks.md +376 -0
  85. data/examples/linked1.md +8 -1
  86. data/implementation-decisions.md +212 -0
  87. data/lib/cached_nested_file_reader.rb +138 -1
  88. data/lib/command_result.rb +27 -6
  89. data/lib/executed_shell_command.rb +512 -0
  90. data/lib/filter.rb +7 -7
  91. data/lib/hash_delegator.rb +403 -350
  92. data/lib/link_history.rb +22 -11
  93. data/lib/markdown_exec/version.rb +1 -1
  94. data/lib/mdoc.rb +103 -44
  95. data/lib/menu.src.yml +110 -83
  96. data/lib/menu.yml +149 -83
  97. data/lib/transformed_shell_command.rb +449 -0
  98. data/lib/wl.rb +15 -0
  99. data/lib/ww.rb +16 -5
  100. data/requirements.md +111 -0
  101. data/semantic-tokens.md +132 -0
  102. data/tasks.md +69 -0
  103. metadata +26 -4
  104. data/docs/ux-blocks-examples.md +0 -120
  105. data/docs/ux-blocks-init-act.md +0 -100
data/docs/ux-blocks.md ADDED
@@ -0,0 +1,376 @@
1
+ # UX Blocks
2
+
3
+ UX blocks create interactive forms that prompt users for input, validate values, and initialize from various sources. This document covers the complete UX block system.
4
+
5
+ ## Overview
6
+
7
+ UX blocks provide an interactive form system for markdown_exec that allows you to:
8
+ - Prompt users for input with custom prompts
9
+ - Validate input using regex patterns
10
+ - Transform validated input using format strings
11
+ - Initialize values from environment variables, commands, or allowed lists
12
+ - Create dynamic selection menus from command output
13
+ - Chain UX blocks with dependencies
14
+
15
+ ## Block Structure
16
+
17
+ A UX block is a fenced code block with type `ux`:
18
+
19
+ ```ux
20
+ name: VARIABLE_NAME
21
+ prompt: Enter a value
22
+ init: Default value
23
+ ```
24
+
25
+ ## Key Fields
26
+
27
+ ### Required Fields
28
+
29
+ - **`name`**: The variable name that will be set (required)
30
+
31
+ ### Optional Fields
32
+
33
+ - **`prompt`**: Text displayed when prompting for input
34
+ - **`init`**: Initial value or initialization method (see Init Phase below)
35
+ - **`act`**: Activation method (see Act Phase below)
36
+ - **`allow`**: List of allowed values for selection
37
+ - **`validate`**: Regex pattern for input validation
38
+ - **`transform`**: Format string for transforming validated input
39
+ - **`format`**: Format string for displaying the value
40
+ - **`echo`**: Shell expression to evaluate
41
+ - **`exec`**: Command to execute
42
+ - **`require`**: List of other UX block names that must be set first
43
+
44
+ ## Init and Act Behavior
45
+
46
+ The `init` and `act` keys determine which other key is read for processing during initialization (when document is loaded) and activation (when block is selected) respectively.
47
+
48
+ ### Init Phase
49
+
50
+ The init phase runs when the document is loaded. The behavior depends on the `init` value:
51
+
52
+ 1. **`init: false`**: No initialization occurs
53
+ 2. **`init: "string"`**: That string becomes the initial value
54
+ 3. **`init: :allow`**: First value from `allow` list is used
55
+ 4. **`init: :echo`**: Value from `echo` key is evaluated and returned
56
+ 5. **`init: :exec`**: Command from `exec` key is executed and stdout is returned
57
+ 6. **`init` not present**: Defaults to first available in order:
58
+ - `:allow` if `allow` exists
59
+ - `:default` if `default` exists
60
+ - `:echo` if `echo` exists
61
+ - `:exec` if `exec` exists
62
+ - `false` if none of the above exist
63
+
64
+ ### Act Phase
65
+
66
+ The act phase runs when the block is activated (selected). The behavior depends on the `act` value:
67
+
68
+ 1. **`act: false`**: Block cannot be activated
69
+ 2. **`act: :allow`**: User selects from `allow` list
70
+ 3. **`act: :echo`**: Value from `echo` key is evaluated and returned
71
+ 4. **`act: :edit`**: User is prompted for input
72
+ 5. **`act: :exec`**: Command from `exec` key is executed and stdout is returned
73
+ 6. **`act` not present**: Defaults to:
74
+ - If `init` is `false`: First available in order: `:allow`, `:echo`, `:edit`, `:exec`
75
+ - Otherwise:
76
+ - `:allow` if `allow` exists
77
+ - `:edit` if `allow` does not exist
78
+
79
+ ## Examples
80
+
81
+ ### Simple Variable Display and Edit
82
+
83
+ ```ux
84
+ init: Guest
85
+ name: USER_NAME
86
+ prompt: Enter your name
87
+ ```
88
+
89
+ - On init: Sets `USER_NAME` to "Guest"
90
+ - On act: Prompts user to enter their name
91
+
92
+ ### Command Output Initialization
93
+
94
+ ```ux
95
+ name: CURRENT_DIR
96
+ init: :exec
97
+ exec: basename $(pwd)
98
+ transform: :chomp
99
+ ```
100
+
101
+ - On init: Executes `basename $(pwd)` and uses output as value
102
+ - On act: Prompts for input (default behavior)
103
+
104
+ ### Echo-based Initialization
105
+
106
+ ```ux
107
+ name: SHELL_VERSION
108
+ init: :echo
109
+ echo: $SHELL
110
+ ```
111
+
112
+ - On init: Evaluates `$SHELL` and uses result as value
113
+ - On act: Evaluates echo string (default behavior)
114
+
115
+ ### Selection from Allowed Values
116
+
117
+ ```ux
118
+ name: ENVIRONMENT
119
+ allow:
120
+ - development
121
+ - staging
122
+ - production
123
+ prompt: Select environment
124
+ ```
125
+
126
+ - On init: Uses first allowed value (development)
127
+ - On act: Shows menu of allowed values for selection
128
+
129
+ ### Email Validation
130
+
131
+ ```ux
132
+ name: USER_EMAIL
133
+ prompt: Enter email address
134
+ validate: '(?<local>[^@]+)@(?<domain>[^@]+)'
135
+ transform: '%{local}@%{domain}'
136
+ ```
137
+
138
+ - Validates input matches email pattern
139
+ - Transforms using captured groups from validation regex
140
+
141
+ ### Version Number Validation
142
+
143
+ ```ux
144
+ name: VERSION
145
+ prompt: Enter version number
146
+ validate: '(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)'
147
+ transform: '%{major}.%{minor}.%{patch}'
148
+ ```
149
+
150
+ - Validates version number format
151
+ - Normalizes format using captured groups
152
+
153
+ ### Git Branch Selection with Validation
154
+
155
+ ```ux
156
+ name: BRANCH_NAME
157
+ init: ":exec"
158
+ exec: "git branch --format='%(refname:short)'"
159
+ validate: '^(?<type>feature|bugfix|hotfix)/(?<ticket>[A-Z]+-\d+)-(?<desc>.+)$'
160
+ transform: "${type}/${ticket}-${desc}"
161
+ prompt: "Select or enter branch name"
162
+ ```
163
+
164
+ - On init: Executes git command to get branch list
165
+ - Validates branch name format
166
+ - Transforms to normalized format
167
+
168
+ ### Environment Configuration with Dependencies
169
+
170
+ ```ux
171
+ name: DATABASE_URL
172
+ require:
173
+ - ENVIRONMENT
174
+ - DB_HOST
175
+ - DB_PORT
176
+ format: "postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
177
+ ```
178
+
179
+ - Requires other UX blocks to be set first
180
+ - Formats final value using required variables
181
+
182
+ ### Multi-step Configuration
183
+
184
+ ```ux
185
+ name: DEPLOY_CONFIG
186
+ require:
187
+ - ENVIRONMENT
188
+ - VERSION
189
+ init: ":echo"
190
+ echo: "Deploying ${VERSION} to ${ENVIRONMENT}"
191
+ act: ":exec"
192
+ exec: "deploy.sh ${ENVIRONMENT} ${VERSION}"
193
+ ```
194
+
195
+ - On init: Evaluates echo string with dependencies
196
+ - On act: Executes deploy script with parameters
197
+
198
+ ### Conditional Initialization
199
+
200
+ ```ux
201
+ name: API_KEY
202
+ init: ":allow"
203
+ allow:
204
+ - ${PROD_API_KEY}
205
+ - ${STAGING_API_KEY}
206
+ - ${DEV_API_KEY}
207
+ require:
208
+ - ENVIRONMENT
209
+ ```
210
+
211
+ - On init: Uses first allowed API key
212
+ - On act: Shows menu of allowed API keys for selection
213
+ - Requires ENVIRONMENT to be set first
214
+
215
+ ### Formatted Output with Validation
216
+
217
+ ```ux
218
+ name: PHONE_NUMBER
219
+ prompt: "Enter phone number"
220
+ validate: '(?<country>\d{1,3})(?<area>\d{3})(?<number>\d{7})'
221
+ transform: "+${country} (${area}) ${number}"
222
+ format: "Phone: ${PHONE_NUMBER}"
223
+ ```
224
+
225
+ - Validates phone number format
226
+ - Transforms to formatted display
227
+ - Uses format string for final display
228
+
229
+ ### Command Output with Transformation
230
+
231
+ ```ux
232
+ name: GIT_STATUS
233
+ init: ":exec"
234
+ exec: "git status --porcelain"
235
+ validate: '(?<status>[AMDR])\s+(?<file>.+)'
236
+ transform: "${status}: ${file}"
237
+ format: "Changes: ${GIT_STATUS}"
238
+ ```
239
+
240
+ - On init: Executes git status command
241
+ - Validates and transforms output
242
+ - Formats for display
243
+
244
+ ## Advanced Patterns
245
+
246
+ ### Echo on Init, Exec on Act
247
+
248
+ ```ux
249
+ name: DEPLOY_CONFIG
250
+ init: :echo
251
+ echo: "Deploying ${VERSION} to ${ENVIRONMENT}"
252
+ act: :exec
253
+ exec: "deploy.sh ${ENVIRONMENT} ${VERSION}"
254
+ ```
255
+
256
+ **Behavior:**
257
+ - On init: Evaluates echo string "Deploying ${VERSION} to ${ENVIRONMENT}"
258
+ - On act: Executes deploy.sh with environment and version parameters
259
+
260
+ ### Allow on Init, Edit on Act
261
+
262
+ ```ux
263
+ name: ENVIRONMENT
264
+ init: :allow
265
+ allow:
266
+ - development
267
+ - staging
268
+ - production
269
+ act: :edit
270
+ prompt: Select environment
271
+ ```
272
+
273
+ **Behavior:**
274
+ - On init: Uses first allowed value (development)
275
+ - On act: Prompts user to select from allowed values
276
+
277
+ ### Exec on Init, Echo on Act
278
+
279
+ ```ux
280
+ name: CURRENT_DIR
281
+ init: :exec
282
+ exec: basename $(pwd)
283
+ act: :echo
284
+ echo: "Current directory: ${CURRENT_DIR}"
285
+ ```
286
+
287
+ **Behavior:**
288
+ - On init: Executes basename command on current directory
289
+ - On act: Evaluates echo string with current directory value
290
+
291
+ ### Allow on Both
292
+
293
+ ```ux
294
+ name: API_KEY
295
+ init: :allow
296
+ allow:
297
+ - ${PROD_API_KEY}
298
+ - ${STAGING_API_KEY}
299
+ - ${DEV_API_KEY}
300
+ act: :allow
301
+ require:
302
+ - ENVIRONMENT
303
+ ```
304
+
305
+ **Behavior:**
306
+ - On init: Uses first allowed API key
307
+ - On act: Shows menu of allowed API keys for selection
308
+
309
+ ### Echo on Both
310
+
311
+ ```ux
312
+ name: SHELL_VERSION
313
+ init: :echo
314
+ echo: $SHELL
315
+ act: :echo
316
+ echo: "Using shell: ${SHELL_VERSION}"
317
+ ```
318
+
319
+ **Behavior:**
320
+ - On init: Gets shell value from environment
321
+ - On act: Evaluates echo string with current shell value
322
+
323
+ ## Validation and Transformation
324
+
325
+ ### Validation Regex
326
+
327
+ The `validate` field uses Ruby regex syntax with named capture groups:
328
+
329
+ ```ux
330
+ validate: '(?<local>[^@]+)@(?<domain>[^@]+)'
331
+ ```
332
+
333
+ This creates capture groups that can be referenced in the `transform` field.
334
+
335
+ ### Transformation Format
336
+
337
+ The `transform` field uses format string syntax with capture group references:
338
+
339
+ ```ux
340
+ transform: '%{local}@%{domain}'
341
+ ```
342
+
343
+ Or with shell variable expansion:
344
+
345
+ ```ux
346
+ transform: "${local}@${domain}"
347
+ ```
348
+
349
+ ### Format Display
350
+
351
+ The `format` field controls how the value is displayed in menus:
352
+
353
+ ```ux
354
+ format: "Phone: ${PHONE_NUMBER}"
355
+ ```
356
+
357
+ ## Dependencies
358
+
359
+ UX blocks can depend on other UX blocks using the `require` field:
360
+
361
+ ```ux
362
+ name: DATABASE_URL
363
+ require:
364
+ - ENVIRONMENT
365
+ - DB_HOST
366
+ - DB_PORT
367
+ ```
368
+
369
+ When a UX block has dependencies, those blocks must be initialized or activated first before this block can be used.
370
+
371
+ ## Related Documentation
372
+
373
+ - [Block Naming Patterns](block-naming-patterns.md) - How block names are parsed
374
+ - [Block Execution Modes](block-execution-modes.md) - Execution mode configuration
375
+ - [Import Options](import-options.md) - Using UX blocks with imports
376
+
data/examples/linked1.md CHANGED
@@ -40,5 +40,12 @@ file: examples/linked2.md
40
40
  ```link :linked2_import_vars +(vars2)
41
41
  file: examples/linked2.md
42
42
  vars:
43
- page2_var_via_environment: for_page2_from_page1_via_current_environment
43
+ page2_var_via_environment: ${PAGE2_VAR_VIA_INHERIT}
44
+ page2_var_via_environment1: ${d1_v1}
45
+ page2_var_via_environment2: for_page2_from_page1_via_current_environment
44
46
  ```
47
+ ```vars :(document_vars)
48
+ d1_v1: 1
49
+ ```
50
+
51
+ ```
@@ -0,0 +1,212 @@
1
+ # Implementation Decisions
2
+
3
+ **STDD Methodology Version**: 1.0.0
4
+
5
+ ## Overview
6
+ This document captures detailed implementation decisions for your project, including specific APIs, data structures, and algorithms. All decisions are cross-referenced with architecture decisions using `[ARCH:*]` tokens and requirements using `[REQ:*]` tokens for traceability.
7
+
8
+ ## 1. Configuration Structure [IMPL:CONFIG_STRUCT] [ARCH:CONFIG_STRUCTURE] [REQ:CONFIGURATION]
9
+
10
+ ### Config Type
11
+ ```[your-language]
12
+ type Config struct {
13
+ // Add your configuration fields here
14
+ Field1 string
15
+ Field2 int
16
+ Field3 bool
17
+ }
18
+ ```
19
+
20
+ ### Default Values
21
+ - Field1: default value
22
+ - Field2: default value
23
+ - Field3: default value
24
+
25
+ ## 2. Core Implementation [IMPL:EXAMPLE_IMPLEMENTATION] [ARCH:EXAMPLE_DECISION] [REQ:EXAMPLE_FEATURE]
26
+
27
+ ### Data Structure
28
+ ```[your-language]
29
+ type ExampleStruct struct {
30
+ Field1 string
31
+ Field2 int
32
+ }
33
+ ```
34
+
35
+ ### Implementation Approach
36
+ - Approach description
37
+ - Key algorithms
38
+ - Performance considerations
39
+
40
+ ### Platform-Specific Considerations
41
+ - Platform 1: Specific considerations
42
+ - Platform 2: Specific considerations
43
+
44
+ ## 3. Error Handling Implementation [IMPL:ERROR_HANDLING] [ARCH:ERROR_HANDLING] [REQ:ERROR_HANDLING]
45
+
46
+ ### Error Types
47
+ ```[your-language]
48
+ var (
49
+ ErrExampleError = errors.New("example error message")
50
+ ErrAnotherError = errors.New("another error message")
51
+ )
52
+ ```
53
+
54
+ ### Error Wrapping
55
+ ```[your-language]
56
+ if err != nil {
57
+ return fmt.Errorf("context: %w", err)
58
+ }
59
+ ```
60
+
61
+ ### Error Reporting
62
+ - Error logging approach
63
+ - Error propagation pattern
64
+ - User-facing error messages
65
+
66
+ ## 4. Testing Implementation [IMPL:TESTING] [ARCH:TESTING_STRATEGY] [REQ:*]
67
+
68
+ **Note**: This implementation realizes the validation criteria specified in `requirements.md` and follows the testing strategy defined in `architecture-decisions.md`. Each test validates specific satisfaction criteria from requirements.
69
+
70
+ ### Unit Test Structure
71
+ ```[your-language]
72
+ func TestExampleFeature(t *testing.T) {
73
+ tests := []struct {
74
+ name string
75
+ input InputType
76
+ expected OutputType
77
+ }{
78
+ {
79
+ name: "test case 1",
80
+ input: inputValue,
81
+ expected: expectedValue,
82
+ },
83
+ }
84
+
85
+ for _, tt := range tests {
86
+ t.Run(tt.name, func(t *testing.T) {
87
+ result := functionUnderTest(tt.input)
88
+ if result != tt.expected {
89
+ t.Errorf("expected %v, got %v", tt.expected, result)
90
+ }
91
+ })
92
+ }
93
+ }
94
+ ```
95
+
96
+ ### Integration Test Structure
97
+ ```[your-language]
98
+ func TestIntegrationScenario(t *testing.T) {
99
+ // Setup
100
+ // Execute
101
+ // Verify
102
+ }
103
+ ```
104
+
105
+ ## 5. Code Style and Conventions [IMPL:CODE_STYLE]
106
+
107
+ ### Naming
108
+ - Use descriptive names
109
+ - Follow language naming conventions
110
+ - Exported types/functions: PascalCase (or language equivalent)
111
+ - Unexported: camelCase (or language equivalent)
112
+
113
+ ### Documentation
114
+ - Package-level documentation
115
+ - Exported function documentation
116
+ - Inline comments for complex logic
117
+ - Examples in test files
118
+
119
+ ### Formatting
120
+ - Use standard formatter for chosen language
121
+ - Use linter for code quality
122
+
123
+ ## 6. Shebang Line Detection Logic [IMPL:SHEBANG_DETECTION] [ARCH:SHEBANG_EXTRACTION] [REQ:SHEBANG_HIDING]
124
+
125
+ ### Detection Algorithm
126
+ ```ruby
127
+ # [REQ:SHEBANG_HIDING] Detect shebang lines at the start of file content
128
+ # [IMPL:SHEBANG_DETECTION] [ARCH:SHEBANG_EXTRACTION] [REQ:SHEBANG_HIDING]
129
+ # Matches the beginning of the first line as '#!' - anything after that matches a shebang
130
+ # Works directly with raw string segments (not NestedLine objects)
131
+ def is_shebang_line?(line, is_first_line)
132
+ return false unless is_first_line
133
+ line.start_with?('#!')
134
+ end
135
+ ```
136
+
137
+ ### Detection Rules
138
+ - Shebang lines must start with `#!` at the beginning of the line (no leading whitespace)
139
+ - Only the first line of file content is considered (index 0)
140
+ - The line must begin with `#!` - anything after that matches a shebang
141
+ - Detection occurs before import directive processing
142
+ - Each file in nested imports is checked independently
143
+
144
+ ### Edge Cases
145
+ - Empty files: No shebang (no first line)
146
+ - Files starting with whitespace before `#!`: Not recognized as shebang (must be at beginning)
147
+ - Files with only shebang: File becomes effectively empty after filtering
148
+ - Import directives on first line: Shebang takes precedence (shebang is first)
149
+
150
+ ## 7. Shebang Line Filtering Implementation [IMPL:SHEBANG_FILTERING] [ARCH:SHEBANG_EXTRACTION] [REQ:SHEBANG_HIDING]
151
+
152
+ ### Filtering Logic
153
+ ```ruby
154
+ # [REQ:SHEBANG_HIDING] Filter shebang lines from processed output
155
+ # [IMPL:SHEBANG_FILTERING] [ARCH:SHEBANG_EXTRACTION] [REQ:SHEBANG_HIDING]
156
+ # Filtering occurs inline during segment reading
157
+ File.readlines(filename, chomp: true).each.with_index do |segment, ind|
158
+ # Skip shebang lines at the beginning of the file
159
+ next if @hide_shebang && is_shebang_line?(segment, ind == 0)
160
+
161
+ # Process remaining lines normally
162
+ # ...
163
+ end
164
+ ```
165
+
166
+ ### Implementation Details
167
+ - Filtering occurs inline in `CachedNestedFileReader#readlines` during segment reading
168
+ - Shebang lines are skipped before they are processed into `NestedLine` objects
169
+ - Applied to both direct file reads and nested imports (via recursive calls)
170
+ - Option `hide_shebang` controls filtering behavior
171
+ - When disabled (`hide_shebang: false`), all lines included
172
+ - When enabled (`hide_shebang: true`), first line (index 0) is skipped if it's a shebang
173
+ - Filtering happens at the source, preventing shebang lines from entering the processing pipeline
174
+ - More efficient than post-processing as it avoids creating `NestedLine` objects for shebang lines
175
+
176
+ ### Integration with CachedNestedFileReader
177
+ - Option stored as instance variable `@hide_shebang` set during initialization
178
+ - Filtering applied inline during the `File.readlines` loop before segment processing
179
+ - Shebang detection uses `is_shebang_line?(segment, ind == 0)` where `segment` is the raw string line
180
+ - Cached results already have shebang filtered (if option was enabled during cache)
181
+ - Recursive calls to `readlines` use the same `@hide_shebang` instance variable, ensuring consistent behavior across nested imports
182
+
183
+ ## 8. CLI Option Implementation in Menu System [IMPL:CLI_OPTION_IMPLEMENTATION] [ARCH:CLI_OPTION_DESIGN] [REQ:SHEBANG_HIDING]
184
+
185
+ ### Menu Configuration
186
+ ```yaml
187
+ # [REQ:SHEBANG_HIDING] CLI option for hiding shebang lines
188
+ # [IMPL:CLI_OPTION_IMPLEMENTATION] [ARCH:CLI_OPTION_DESIGN] [REQ:SHEBANG_HIDING]
189
+ - :opt_name: hide_shebang
190
+ :env_var: MDE_HIDE_SHEBANG
191
+ :description: Hide shebang lines in document output
192
+ :arg_name: BOOL
193
+ :default: true
194
+ :procname: val_as_bool
195
+ ```
196
+
197
+ ### Option Access
198
+ - CLI: `--hide-shebang` (enables) / `--no-hide-shebang` (disables)
199
+ - Environment: `MDE_HIDE_SHEBANG=true` or `MDE_HIDE_SHEBANG=false`
200
+ - Configuration file: `hide_shebang: true` in `.mde.yml`
201
+ - Default: `true` (shebang lines hidden by default)
202
+
203
+ ### Option Propagation
204
+ - Option available in `@options` hash via `MarkParse#base_options`
205
+ - Option passed to `CachedNestedFileReader` during initialization or read calls
206
+ - Option value accessible as `options[:hide_shebang]` (boolean)
207
+
208
+ ### Integration Points
209
+ - `MarkParse#base_options`: Includes option in base options hash
210
+ - `CachedNestedFileReader#initialize`: Option passed as parameter (or via options hash)
211
+ - `CachedNestedFileReader#readlines`: Option used to control filtering behavior
212
+