From 4c851fa7a7014ef4ca4d516e4cbe89ca23a49ca8 Mon Sep 17 00:00:00 2001 From: maxim Date: Sat, 13 Dec 2025 01:11:59 -0300 Subject: [PATCH 01/12] tests: add coverage for multi-statement command output handling Add tests for check-print-append, get-last-span to verify correct output detection when commands contain source, overlay, alias, or use statements in multi-statement contexts. --- tests/test_commands.nu | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/test_commands.nu b/tests/test_commands.nu index 2c65a6d..e229356 100644 --- a/tests/test_commands.nu +++ b/tests/test_commands.nu @@ -290,6 +290,46 @@ def "check-print-append returns false for print ending" [] { assert equal (check-print-append "ls | print") false } +@test +def "check-print-append returns false for source statements" [] { + assert equal (check-print-append "source a.nu") false + assert equal (check-print-append "overlay use foo") false + assert equal (check-print-append "alias ll = ls -la") false +} + +@test +def "check-print-append handles multi-statement commands" [] { + # Last span is echo - should be true + assert equal (check-print-append "source a.nu; echo abc") true + # Last span is source - should be false + assert equal (check-print-append "echo abc; source a.nu") false + # Multi-line: last is echo + assert equal (check-print-append "source a.nu\necho hello") true + # Last span is use - should be false + assert equal (check-print-append "ls; use std") false +} + +# ============================================================================= +# Tests for get-last-span +# ============================================================================= + +@test +def "get-last-span returns whole command for simple commands" [] { + assert equal (get-last-span "ls") "ls" + assert equal (get-last-span "echo hello") "echo hello" +} + +@test +def "get-last-span returns last statement after semicolon" [] { + assert equal (get-last-span "source a.nu; echo abc") "echo abc" + assert equal (get-last-span "echo abc; source a.nu") "source a.nu" +} + +@test +def "get-last-span handles multi-line commands" [] { + assert equal (get-last-span "source a.nu\necho hello") "echo hello" +} + # ============================================================================= # Tests for modify-path # ============================================================================= From 8d9efd575acba457aaee43ac3758c5c4f79570d1 Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 13 Dec 2025 01:16:58 -0300 Subject: [PATCH 02/12] fix: add source, overlay, alias to check-print-append keywords These statements don't produce output that should be appended. --- numd/commands.nu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numd/commands.nu b/numd/commands.nu index c7cee27..7e97b45 100644 --- a/numd/commands.nu +++ b/numd/commands.nu @@ -681,7 +681,7 @@ export def check-print-append [ ( $last_span !~ '(;|print|null)$' - and $last_span !~ '\b(let|mut|def|use)\b' + and $last_span !~ '\b(let|mut|def|use|source|overlay|alias)\b' and $last_span !~ '(^|;|\n) ?(? Date: Sat, 13 Dec 2025 01:22:37 -0300 Subject: [PATCH 03/12] refactor: make example outputs deterministic - Replace `sys host | get boot_time` with `str length` in README - Use fixed datetime instead of `date now` in timezone example - Update error-with-try.md with current nushell error format --- README.md | 4 ++-- .../4_book_working_with_lists/working_with_lists.md | 11 ++++++----- .../working_with_lists.md_intermed.nu | 6 ++++-- z_examples/6_edge_cases/error-with-try.md | 3 ++- z_examples/99_strip_markdown/working_with_lists.nu | 3 ++- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1ceee7e..f473771 100644 --- a/README.md +++ b/README.md @@ -212,8 +212,8 @@ ls z_examples | sort-by name | reject modified size # => │ z_examples/9_other │ dir │ # => ╰──────────────────name───────────────────┴─type─╯ -sys host | get boot_time -# => Fri Dec 5 03:49:33 2025 +'hello world' | str length +# => 11 2 + 2 # => 4 diff --git a/z_examples/4_book_working_with_lists/working_with_lists.md b/z_examples/4_book_working_with_lists/working_with_lists.md index 9ee25cd..fb3984b 100644 --- a/z_examples/4_book_working_with_lists/working_with_lists.md +++ b/z_examples/4_book_working_with_lists/working_with_lists.md @@ -329,11 +329,12 @@ be converted to a separate row with a single column: ```nu let zones = [UTC CET Europe/Moscow Asia/Yekaterinburg] # Show world clock for selected time zones -$zones | wrap 'Zone' | upsert Time {|row| (date now | date to-timezone $row.Zone | format date '%Y.%m.%d %H:%M')} +let base_time = '2024-01-15 12:00:00' | into datetime --timezone UTC +$zones | wrap 'Zone' | upsert Time {|row| ($base_time | date to-timezone $row.Zone | format date '%Y.%m.%d %H:%M')} # => ╭────────Zone────────┬───────Time───────╮ -# => │ UTC │ 2025.12.11 01:24 │ -# => │ CET │ 2025.12.11 02:24 │ -# => │ Europe/Moscow │ 2025.12.11 04:24 │ -# => │ Asia/Yekaterinburg │ 2025.12.11 06:24 │ +# => │ UTC │ 2024.01.15 15:00 │ +# => │ CET │ 2024.01.15 16:00 │ +# => │ Europe/Moscow │ 2024.01.15 18:00 │ +# => │ Asia/Yekaterinburg │ 2024.01.15 20:00 │ # => ╰────────Zone────────┴───────Time───────╯ ``` diff --git a/z_examples/4_book_working_with_lists/working_with_lists.md_intermed.nu b/z_examples/4_book_working_with_lists/working_with_lists.md_intermed.nu index fadafa4..8e6ee98 100644 --- a/z_examples/4_book_working_with_lists/working_with_lists.md_intermed.nu +++ b/z_examples/4_book_working_with_lists/working_with_lists.md_intermed.nu @@ -292,10 +292,12 @@ print '' ```nu" | print "let zones = [UTC CET Europe/Moscow Asia/Yekaterinburg] # Show world clock for selected time zones -$zones | wrap 'Zone' | upsert Time {|row| (date now | date to-timezone $row.Zone | format date '%Y.%m.%d %H:%M')}" | nu-highlight | print +let base_time = '2024-01-15 12:00:00' | into datetime --timezone UTC +$zones | wrap 'Zone' | upsert Time {|row| ($base_time | date to-timezone $row.Zone | format date '%Y.%m.%d %H:%M')}" | nu-highlight | print let zones = [UTC CET Europe/Moscow Asia/Yekaterinburg] # Show world clock for selected time zones -$zones | wrap 'Zone' | upsert Time {|row| (date now | date to-timezone $row.Zone | format date '%Y.%m.%d %H:%M')} | table --width 120 | default '' | into string | lines | each {$'# => ($in)' | str trim --right} | str join (char nl) | str replace -r '\s*$' "\n" | print; print '' +let base_time = '2024-01-15 12:00:00' | into datetime --timezone UTC +$zones | wrap 'Zone' | upsert Time {|row| ($base_time | date to-timezone $row.Zone | format date '%Y.%m.%d %H:%M')} | table --width 120 | default '' | into string | lines | each {$'# => ($in)' | str trim --right} | str join (char nl) | str replace -r '\s*$' "\n" | print; print '' print '' "```" | print diff --git a/z_examples/6_edge_cases/error-with-try.md b/z_examples/6_edge_cases/error-with-try.md index 8fd11f4..02f3be9 100644 --- a/z_examples/6_edge_cases/error-with-try.md +++ b/z_examples/6_edge_cases/error-with-try.md @@ -17,6 +17,7 @@ lssomething # => : ^^^^^|^^^^^ # => : `-- Command `lssomething` not found # => `---- -# => help: `lssomething` is neither a Nushell built-in or a known external command +# => help: `lssomething` is neither a Nushell built-in or a known external +# => command # => ``` diff --git a/z_examples/99_strip_markdown/working_with_lists.nu b/z_examples/99_strip_markdown/working_with_lists.nu index f705893..6c33a7c 100644 --- a/z_examples/99_strip_markdown/working_with_lists.nu +++ b/z_examples/99_strip_markdown/working_with_lists.nu @@ -143,4 +143,5 @@ $scores | all {|elt| $elt mod 2 == 0 } # false # ```nu let zones = [UTC CET Europe/Moscow Asia/Yekaterinburg] # Show world clock for selected time zones -$zones | wrap 'Zone' | upsert Time {|row| (date now | date to-timezone $row.Zone | format date '%Y.%m.%d %H:%M')} +let base_time = '2024-01-15 12:00:00' | into datetime --timezone UTC +$zones | wrap 'Zone' | upsert Time {|row| ($base_time | date to-timezone $row.Zone | format date '%Y.%m.%d %H:%M')} From 0746a978436851989719f239d78f58be76db12af Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 13 Dec 2025 01:31:30 -0300 Subject: [PATCH 04/12] refactor: unify try-catch wrapper functions into single implementation Consolidates `create-catch-error-current-instance` and `create-catch-error-outside` into a single `wrap-in-try-catch` function with a `--new-instance` flag. This reduces code duplication and simplifies the call site in `create-execution-code`. --- numd/commands.nu | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/numd/commands.nu b/numd/commands.nu index 7e97b45..3a26b21 100644 --- a/numd/commands.nu +++ b/numd/commands.nu @@ -330,11 +330,7 @@ export def create-execution-code [ let code_execution = $code_content | remove-comments-plus | if 'try' in $fence_options { - if 'new-instance' in $fence_options { - create-catch-error-outside - } else { - create-catch-error-current-instance - } + wrap-in-try-catch --new-instance=('new-instance' in $fence_options) } else { } | if 'no-output' in $fence_options { } else { # separate-block: output goes to a separate ```output-numd``` fence @@ -716,24 +712,25 @@ export def generate-table-statement []: string -> string { $"($in) | table --width ($env.numd?.table-width? | default 120)" } -# Generate a try-catch block to handle errors in the current Nushell instance. +# Wrap code in a try-catch block to handle errors gracefully. # -# > 'ls' | create-catch-error-current-instance +# > 'ls' | wrap-in-try-catch # try {ls} catch {|error| $error} -export def create-catch-error-current-instance []: string -> string { - $"try {($in)} catch {|error| $error}" -} - -# Execute the command outside to obtain a formatted error message if any. # -# > 'ls' | create-catch-error-outside +# > 'ls' | wrap-in-try-catch --new-instance # /Users/user/.cargo/bin/nu -c "ls" | complete | if ($in.exit_code != 0) {get stderr} else {get stdout} -export def create-catch-error-outside []: string -> string { - escape-special-characters-and-quote - | ( - $'($nu.current-exe) -c ($in)' + - " | complete | if ($in.exit_code != 0) {get stderr} else {get stdout}" - ) +export def wrap-in-try-catch [ + --new-instance # execute in a separate Nushell instance to get formatted error messages +]: string -> string { + if $new_instance { + escape-special-characters-and-quote + | ( + $'($nu.current-exe) -c ($in)' + + " | complete | if ($in.exit_code != 0) {get stderr} else {get stdout}" + ) + } else { + $"try {($in)} catch {|error| $error}" + } } # Generate a fenced code block for output with a specific format. From 2679782af7f966eddca60f00d353bb99b6fd91b9 Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 13 Dec 2025 01:40:48 -0300 Subject: [PATCH 05/12] refactor: extract output formatting logic into apply-output-formatting helper Extracts the output formatting logic from create-execution-code into a new apply-output-formatting helper function. This improves code organization by separating concerns - the new function specifically handles 'no-output' and 'separate-block' fence options with clearer control flow. --- numd/commands.nu | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/numd/commands.nu b/numd/commands.nu index 3a26b21..95ab3f6 100644 --- a/numd/commands.nu +++ b/numd/commands.nu @@ -316,6 +316,19 @@ export def match-action [ } } +# Apply output formatting based on fence options (separate-block vs inline `# =>`). +def apply-output-formatting [fence_options: list]: string -> string { + let input = $in + + if 'no-output' in $fence_options { return $input } + + $input + | if 'separate-block' in $fence_options { create-fence-output } else { } + | if not (check-print-append $input) { } else { + create-indented-output | generate-print-statement + } +} + # Generate code for execution in the intermediate script within a given code fence. # # > 'ls | sort-by modified -r' | create-execution-code ['no-output'] | save z_examples/999_numd_internals/create-execution-code_0.nu -f @@ -323,7 +336,6 @@ export def create-execution-code [ fence_options: list ]: string -> string { let code_content = $in - # let fence_options = $env.numd.current_block_options let highlighted_command = $code_content | create-highlight-command @@ -332,15 +344,7 @@ export def create-execution-code [ | if 'try' in $fence_options { wrap-in-try-catch --new-instance=('new-instance' in $fence_options) } else { } - | if 'no-output' in $fence_options { } else { - # separate-block: output goes to a separate ```output-numd``` fence - # default: output is inline with `# =>` prefix - if 'separate-block' in $fence_options { create-fence-output } else { } - | if (check-print-append $in) { - create-indented-output - | generate-print-statement - } else { } - } + | apply-output-formatting $fence_options | $in + (char nl) # Always print a blank line after each command group to preserve visual separation | $in + "print ''" From ae4667297694238daceb3bca277c1842d2803a9b Mon Sep 17 00:00:00 2001 From: maxim Date: Sat, 13 Dec 2025 16:35:49 -0300 Subject: [PATCH 06/12] refactor: style --- numd/commands.nu | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/numd/commands.nu b/numd/commands.nu index 95ab3f6..2723aa1 100644 --- a/numd/commands.nu +++ b/numd/commands.nu @@ -318,15 +318,12 @@ export def match-action [ # Apply output formatting based on fence options (separate-block vs inline `# =>`). def apply-output-formatting [fence_options: list]: string -> string { - let input = $in - - if 'no-output' in $fence_options { return $input } - - $input + if 'no-output' in $fence_options { return $in } else { } | if 'separate-block' in $fence_options { create-fence-output } else { } - | if not (check-print-append $input) { } else { - create-indented-output | generate-print-statement - } + | if (check-print-append $in) { + create-indented-output + | generate-print-statement + } else { } } # Generate code for execution in the intermediate script within a given code fence. From 9cbab2f8d1e42a77d268d725570c256bbd5e97d0 Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 13 Dec 2025 14:44:58 -0300 Subject: [PATCH 07/12] docs: correct output format conventions in CLAUDE.md Remove inaccurate description of REPL-style `>` command handling which doesn't exist in the codebase. Replace with accurate documentation of how numd actually processes code blocks: splitting by blank lines into command groups, executing each group separately, and handling `# =>` output markers. --- CLAUDE.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index fc96891..aa37338 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -53,9 +53,11 @@ Blocks support options in the infostring (e.g., ` ```nushell try, no-output `): ### Output Format Conventions -- Lines starting with `>` are treated as REPL-style commands (executed line-by-line) -- Lines starting with `# =>` contain output from previous command -- Blocks without `>` are executed as a single script unit +- Code blocks are split by blank lines (double newlines) into command groups +- Each command group is executed separately via `split-by-blank-lines` +- Lines starting with `# =>` contain output from previous command group +- Plain `#` comments are preserved; `# =>` output lines are regenerated on each run +- Use `separate-block` fence option to output results in a separate code block instead of inline `# =>` ## Testing From 35f4c964f10e83f3e386583403a5ed758f5c7023 Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 13 Dec 2025 14:48:07 -0300 Subject: [PATCH 08/12] docs: update CLAUDE.md with accurate module structure and code block options - Update commands.nu line count from ~840 to ~865 lines - Add missing nu-utils/ directory to module structure - Document separate-block/s option for code block output formatting - Correct Expected Non-Zero Diffs section to reference actual dynamic content (git tag instead of non-existent sys host boot_time) - Clarify that Nushell version changes affect table rendering and error formatting --- CLAUDE.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index aa37338..e5d7e60 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,7 +30,8 @@ use numd; numd clear-outputs path/to/file.md --strip-markdown --echo ### Module Structure (`numd/`) - **mod.nu**: Entry point exporting public commands (`run`, `clear-outputs`, `list-code-options`, `capture start/stop`, `parse-help`, `parse-frontmatter`, `to md-with-frontmatter`) -- **commands.nu**: Core implementation (~840 lines) containing all main logic +- **commands.nu**: Core implementation (~865 lines) containing all main logic +- **nu-utils/**: Helper utilities (`cprint.nu`, `str repeat.nu`) - **parse.nu**: Frontmatter parsing utilities for YAML frontmatter in markdown ### Core Processing Pipeline (in `commands.nu`) @@ -50,6 +51,7 @@ Blocks support options in the infostring (e.g., ` ```nushell try, no-output `): - `no-output` / `O`: Execute but hide output - `try` / `t`: Wrap in try-catch - `new-instance` / `n`: Execute in separate Nushell instance +- `separate-block` / `s`: Output results in separate code block instead of inline `# =>` ### Output Format Conventions @@ -91,10 +93,10 @@ Example files serve as integration tests - use both the Levenshtein stats and `g ### Expected Non-Zero Diffs Some files legitimately differ on each run due to: -- **Dynamic content**: `sys host | get boot_time` in README.md, timezone examples in `working_with_lists.md` -- **Nushell version changes**: Error message formatting, etc +- **Dynamic content**: `git tag` output in README.md (version changes over time) +- **Nushell version changes**: Error message formatting, table rendering differences -A zero `levenshtein_dist` for most files + expected diffs in time-dependent files = passing tests. +A zero `levenshtein_dist` for most files + expected diffs in dynamic content files = passing tests. ## Configuration From fe2f583e1764ada27cc9316d6f8f3250d1faa995 Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 13 Dec 2025 14:58:01 -0300 Subject: [PATCH 09/12] docs: document README update step in integration testing workflow Add step 3 to Integration Tests section noting that `numd run README.md` is executed to update README with latest outputs during the testing-integration command. --- CLAUDE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index e5d7e60..12a3c2a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -86,7 +86,8 @@ Unit tests use [nutest](https://github.com/vyadh/nutest) framework. Tests import The `testing-integration` command: 1. Runs all example files in `z_examples/` through numd 2. Generates stripped `.nu` versions in `z_examples/99_strip_markdown/` -3. Reports Levenshtein distance and diff stats to detect changes +3. Runs `numd run README.md` to update README with latest outputs +4. Reports Levenshtein distance and diff stats to detect changes Example files serve as integration tests - use both the Levenshtein stats and `git diff` to verify changes. From 182f2d03aca3dbe79cbe52743a395e53d53b6917 Mon Sep 17 00:00:00 2001 From: maxim Date: Sat, 13 Dec 2025 16:43:18 -0300 Subject: [PATCH 10/12] refactor: rename commands for clarity --- CLAUDE.md | 2 +- README.md | 2 +- numd/commands.nu | 88 ++++++------ tests/test_commands.nu | 136 +++++++++--------- toolkit.nu | 8 +- .../numd_commands_explanations.md | 8 +- .../numd_commands_explanations.md_intermed.nu | 12 +- .../numd_commands_explanations.nu | 6 +- 8 files changed, 131 insertions(+), 131 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 12a3c2a..7e51866 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -36,7 +36,7 @@ use numd; numd clear-outputs path/to/file.md --strip-markdown --echo ### Core Processing Pipeline (in `commands.nu`) -1. **`find-code-blocks`**: Parses markdown into a table classifying each block by type (`text`, ` ```nushell `, ` ```output-numd `) and action (`execute`, `print-as-it-is`, `delete`) +1. **`parse-markdown-to-blocks`**: Parses markdown into a table classifying each block by type (`text`, ` ```nushell `, ` ```output-numd `) and action (`execute`, `print-as-it-is`, `delete`) 2. **`decorate-original-code-blocks`** + **`generate-intermediate-script`**: Transforms executable code blocks into a temporary `.nu` script with markers for output capture diff --git a/README.md b/README.md index f473771..76205c8 100644 --- a/README.md +++ b/README.md @@ -250,7 +250,7 @@ nu toolkit.nu testing-integration ### Unit tests -Unit tests in `tests/` use the [nutest](https://github.com/vyadh/nutest) framework to test internal functions like `find-code-blocks`, `match-action`, `extract-fence-options`, etc. +Unit tests in `tests/` use the [nutest](https://github.com/vyadh/nutest) framework to test internal functions like `parse-markdown-to-blocks`, `classify-block-action`, `extract-fence-options`, etc. ### Integration tests diff --git a/numd/commands.nu b/numd/commands.nu index 2723aa1..9e20b61 100644 --- a/numd/commands.nu +++ b/numd/commands.nu @@ -22,13 +22,13 @@ export def run [ } else { } let original_md_table = $original_md - | toggle-output-fences # should be unnecessary for new files - | find-code-blocks + | convert-output-fences # should be unnecessary for new files + | parse-markdown-to-blocks load-config $config_path --prepend_code $prepend_code --table_width $table_width let intermediate_script_path = $save_intermed_script - | default ($file | modify-path --prefix $'numd-temp-(generate-timestamp)' --extension '.nu') + | default ($file | build-modified-path --prefix $'numd-temp-(generate-timestamp)' --extension '.nu') # We don't use a temp directory here as the code in `md` files might contain relative paths, # which will only work if we execute the intermediate script from the same folder. @@ -49,7 +49,7 @@ export def run [ let updated_md_ansi = merge-markdown $original_md_table $nu_res_with_block_index | clean-markdown - | toggle-output-fences --back + | convert-output-fences --back # if $save_intermed_script param wasn't set - remove the temporary intermediate script if $save_intermed_script == null { rm $intermediate_script_path } @@ -83,8 +83,8 @@ export def clear-outputs [ --strip-markdown # keep only Nushell script, strip all markdown tags ]: [nothing -> string nothing -> nothing] { let original_md_table = open -r $file - | toggle-output-fences - | find-code-blocks + | convert-output-fences + | parse-markdown-to-blocks let result_md_path = $result_md_path | default $file @@ -94,7 +94,7 @@ export def clear-outputs [ | items {|block_index block_lines| $block_lines.line.0 | where $it !~ '^# => ?' # strip `# =>` output lines, preserve plain `#` comments - | prepend (mark-code-block $block_index) + | prepend (code-block-marker $block_index) } | flatten | extract-block-index @@ -259,7 +259,7 @@ export def 'parse-help' [ ### # Detect code blocks in a markdown string and return a table with their line numbers and info strings. -export def find-code-blocks []: string -> table, action: string> { +export def parse-markdown-to-blocks []: string -> table, action: string> { let file_lines = $in | lines let row_type = $file_lines | each { @@ -298,10 +298,10 @@ export def find-code-blocks []: string -> table string { match $row_type { @@ -320,24 +320,24 @@ export def match-action [ def apply-output-formatting [fence_options: list]: string -> string { if 'no-output' in $fence_options { return $in } else { } | if 'separate-block' in $fence_options { create-fence-output } else { } - | if (check-print-append $in) { - create-indented-output + | if (can-append-print $in) { + generate-inline-output-pipeline | generate-print-statement } else { } } # Generate code for execution in the intermediate script within a given code fence. # -# > 'ls | sort-by modified -r' | create-execution-code ['no-output'] | save z_examples/999_numd_internals/create-execution-code_0.nu -f -export def create-execution-code [ +# > 'ls | sort-by modified -r' | generate-block-execution ['no-output'] | save z_examples/999_numd_internals/generate-block-execution_0.nu -f +export def generate-block-execution [ fence_options: list ]: string -> string { let code_content = $in - let highlighted_command = $code_content | create-highlight-command + let highlighted_command = $code_content | generate-highlight-print let code_execution = $code_content - | remove-comments-plus + | trim-trailing-comments | if 'try' in $fence_options { wrap-in-try-catch --new-instance=('new-instance' in $fence_options) } else { } @@ -351,14 +351,14 @@ export def create-execution-code [ # Generate additional service code necessary for execution and capturing results, while preserving the original code. export def decorate-original-code-blocks [ - md_classified: table, action: string> # classified markdown table from find-code-blocks + md_classified: table, action: string> # classified markdown table from parse-markdown-to-blocks ]: nothing -> table, action: string, code: string> { $md_classified | where action == 'execute' | insert code {|i| $i.line | execute-block-lines ($i.row_type | extract-fence-options) - | generate-tags $i.block_index $i.row_type + | generate-block-markers $i.block_index $i.row_type } } @@ -396,9 +396,9 @@ export def execute-block-lines [ if ($trimmed | is-empty) { '' } else if ($trimmed | lines | all { $in =~ '^#' }) { - $group | create-highlight-command + $group | generate-highlight-print } else { - $group | create-execution-code $fence_options + $group | generate-block-execution $fence_options } } } @@ -412,11 +412,11 @@ export def split-by-blank-lines []: string -> list { # Parse block indices from Nushell output lines and return a table with the original markdown line numbers. export def extract-block-index []: list -> table { - let clean_lines = skip until { $in =~ (mark-code-block) } + let clean_lines = skip until { $in =~ (code-block-marker) } let block_index = $clean_lines | each { - if $in =~ $"^(mark-code-block)\\d+$" { + if $in =~ $"^(code-block-marker)\\d+$" { split row '-' | last | into int } else { -1 @@ -434,7 +434,7 @@ export def extract-block-index []: list -> table string { } # Replacement is needed to distinguish the blocks with outputs from blocks with just ```. -# `find-code-blocks` works only with lines without knowing the previous lines. +# `parse-markdown-to-blocks` works only with lines without knowing the previous lines. # -# > "```nu\n123\n```\n\nOutput:\n\n```\n123" | toggle-output-fences | to json +# > "```nu\n123\n```\n\nOutput:\n\n```\n123" | convert-output-fences | to json # "```nu\n123\n```\n```output-numd\n123" -export def toggle-output-fences [ +export def convert-output-fences [ a = "\n```\n\nOutput:\n\n```\n" # I set variables here to prevent collecting $in var b = "\n```\n```output-numd\n" --back @@ -490,7 +490,7 @@ export def compute-change-stats [ let new_file_content = $new_file | ansi strip let nushell_blocks = $new_file_content - | find-code-blocks + | parse-markdown-to-blocks | where action == 'execute' | get block_index | uniq @@ -591,27 +591,27 @@ export def execute-intermediate-script [ # Generate a unique identifier for code blocks in markdown to distinguish their output. # -# > mark-code-block 3 +# > code-block-marker 3 # #code-block-marker-open-3 -export def mark-code-block [ +export def code-block-marker [ index?: int --end ]: nothing -> string { $"#code-block-marker-open-($index)" | if $end { str replace 'open' 'close' } else { } } -# TODO NUON can be used in mark-code-blocks to set display options +# TODO NUON can be used in code-block-markers to set display options # Generate a command to highlight code using Nushell syntax highlighting. -# > 'ls' | create-highlight-command +# > 'ls' | generate-highlight-print # "ls" | nu-highlight | print -export def create-highlight-command []: string -> string { +export def generate-highlight-print []: string -> string { escape-special-characters-and-quote | $"($in) | nu-highlight | print(char nl)(char nl)" } # Trim comments and extra whitespace from code blocks for use in the generated script. -export def remove-comments-plus []: string -> string { +export def trim-trailing-comments []: string -> string { str replace -r '[\s\n]+$' '' # trim newlines and spaces from the end of a line | str replace -r '\s+#.*$' '' # remove comments from the last line. Might spoil code blocks with the # symbol, used not for commenting } @@ -663,15 +663,15 @@ export def get-last-span [ # Check if the command can have `| print` appended by analyzing its last span for semicolons or declaration keywords. # -# > check-print-append 'let a = ls' +# > can-append-print 'let a = ls' # false # -# > check-print-append 'ls' +# > can-append-print 'ls' # true # -# > check-print-append 'mut a = 1; $a = 2' +# > can-append-print 'mut a = 1; $a = 2' # false -export def check-print-append [ +export def can-append-print [ command: string ]: nothing -> bool { let last_span = get-last-span $command @@ -685,9 +685,9 @@ export def check-print-append [ # Generate indented output for better visual formatting. # -# > 'ls' | create-indented-output +# > 'ls' | generate-inline-output-pipeline # ls | table | lines | each {$'# => ($in)' | str trim --right} | str join (char nl) -export def create-indented-output [ +export def generate-inline-output-pipeline [ --indent: string = '# => ' # prefix string for each output line ]: string -> string { generate-table-statement @@ -748,13 +748,13 @@ export def generate-print-lines []: list -> string { } # Generate marker tags and code block delimiters for tracking output in the intermediate script. -export def generate-tags [ +export def generate-block-markers [ block_number: int # index of the code block in the markdown fence: string # the original fence line (e.g., '```nushell') ]: list -> string { let input = $in - mark-code-block $block_number + code-block-marker $block_number | append $fence | generate-print-lines | append $input @@ -780,9 +780,9 @@ export def extract-fence-options []: string -> list { # Modify a path by adding a prefix, suffix, extension, or parent directory. # -# > 'numd/capture.nu' | modify-path --extension '.md' --prefix 'pref_' --suffix '_suf' --parent_dir abc +# > 'numd/capture.nu' | build-modified-path --extension '.md' --prefix 'pref_' --suffix '_suf' --parent_dir abc # numd/abc/pref_capture_suf.nu.md -export def modify-path [ +export def build-modified-path [ --prefix: string --suffix: string --extension: string @@ -803,7 +803,7 @@ export def create-file-backup [ ]: nothing -> nothing { $file_path | if ($in | path exists) and ($in | path type) == 'file' { - modify-path --parent_dir 'zzz_md_backups' --suffix $'-(generate-timestamp)' + build-modified-path --parent_dir 'zzz_md_backups' --suffix $'-(generate-timestamp)' | mv $file_path $in } } diff --git a/tests/test_commands.nu b/tests/test_commands.nu index e229356..ee9085c 100644 --- a/tests/test_commands.nu +++ b/tests/test_commands.nu @@ -5,12 +5,12 @@ use std/testing * use ../numd/commands.nu * # ============================================================================= -# Tests for find-code-blocks +# Tests for parse-markdown-to-blocks # ============================================================================= @test -def "find-code-blocks detects nushell block" [] { - let result = "```nushell\necho hello\n```" | find-code-blocks +def "parse-markdown-to-blocks detects nushell block" [] { + let result = "```nushell\necho hello\n```" | parse-markdown-to-blocks assert equal ($result | length) 1 assert equal $result.0.row_type "```nushell" @@ -18,8 +18,8 @@ def "find-code-blocks detects nushell block" [] { } @test -def "find-code-blocks detects nu block" [] { - let result = "```nu\nls\n```" | find-code-blocks +def "parse-markdown-to-blocks detects nu block" [] { + let result = "```nu\nls\n```" | parse-markdown-to-blocks assert equal ($result | length) 1 assert equal $result.0.row_type "```nu" @@ -27,15 +27,15 @@ def "find-code-blocks detects nu block" [] { } @test -def "find-code-blocks handles no-run option" [] { - let result = "```nushell no-run\necho hello\n```" | find-code-blocks +def "parse-markdown-to-blocks handles no-run option" [] { + let result = "```nushell no-run\necho hello\n```" | parse-markdown-to-blocks assert equal $result.0.action "print-as-it-is" } @test -def "find-code-blocks handles text blocks" [] { - let result = "Some text\nMore text" | find-code-blocks +def "parse-markdown-to-blocks handles text blocks" [] { + let result = "Some text\nMore text" | parse-markdown-to-blocks assert equal ($result | length) 1 assert equal $result.0.row_type "text" @@ -43,7 +43,7 @@ def "find-code-blocks handles text blocks" [] { } @test -def "find-code-blocks handles mixed content" [] { +def "parse-markdown-to-blocks handles mixed content" [] { let md = "# Header ```nushell @@ -56,7 +56,7 @@ Some text echo skip ```" - let result = $md | find-code-blocks + let result = $md | parse-markdown-to-blocks assert equal ($result | length) 4 assert equal ($result | where action == "execute" | length) 1 @@ -64,38 +64,38 @@ echo skip } # ============================================================================= -# Tests for match-action +# Tests for classify-block-action # ============================================================================= @test -def "match-action returns execute for nushell" [] { - assert equal (match-action "```nushell") "execute" +def "classify-block-action returns execute for nushell" [] { + assert equal (classify-block-action "```nushell") "execute" } @test -def "match-action returns execute for nu" [] { - assert equal (match-action "```nu") "execute" +def "classify-block-action returns execute for nu" [] { + assert equal (classify-block-action "```nu") "execute" } @test -def "match-action returns print-as-it-is for no-run" [] { - assert equal (match-action "```nushell no-run") "print-as-it-is" +def "classify-block-action returns print-as-it-is for no-run" [] { + assert equal (classify-block-action "```nushell no-run") "print-as-it-is" } @test -def "match-action returns delete for output-numd" [] { - assert equal (match-action "```output-numd") "delete" +def "classify-block-action returns delete for output-numd" [] { + assert equal (classify-block-action "```output-numd") "delete" } @test -def "match-action returns print-as-it-is for text" [] { - assert equal (match-action "text") "print-as-it-is" +def "classify-block-action returns print-as-it-is for text" [] { + assert equal (classify-block-action "text") "print-as-it-is" } @test -def "match-action returns print-as-it-is for other languages" [] { - assert equal (match-action "```python") "print-as-it-is" - assert equal (match-action "```rust") "print-as-it-is" +def "classify-block-action returns print-as-it-is for other languages" [] { + assert equal (classify-block-action "```python") "print-as-it-is" + assert equal (classify-block-action "```rust") "print-as-it-is" } # ============================================================================= @@ -164,17 +164,17 @@ def "convert-short-options keeps long options unchanged" [] { } # ============================================================================= -# Tests for mark-code-block +# Tests for code-block-marker # ============================================================================= @test -def "mark-code-block generates open marker" [] { - assert equal (mark-code-block 5) "#code-block-marker-open-5" +def "code-block-marker generates open marker" [] { + assert equal (code-block-marker 5) "#code-block-marker-open-5" } @test -def "mark-code-block generates close marker" [] { - assert equal (mark-code-block 3 --end) "#code-block-marker-close-3" +def "code-block-marker generates close marker" [] { + assert equal (code-block-marker 3 --end) "#code-block-marker-close-3" } # ============================================================================= @@ -215,22 +215,22 @@ def "clean-markdown ensures single trailing newline" [] { } # ============================================================================= -# Tests for toggle-output-fences +# Tests for convert-output-fences # ============================================================================= @test -def "toggle-output-fences converts output format" [] { +def "convert-output-fences converts output format" [] { let input = "```nu\n123\n```\n\nOutput:\n\n```\n456\n```" - let result = $input | toggle-output-fences + let result = $input | convert-output-fences assert ($result =~ "output-numd") assert ($result !~ "Output:") } @test -def "toggle-output-fences converts back" [] { +def "convert-output-fences converts back" [] { let input = "```nu\n123\n```\n```output-numd\n456\n```" - let result = $input | toggle-output-fences --back + let result = $input | convert-output-fences --back assert ($result =~ "Output:") assert ($result !~ "output-numd") @@ -255,58 +255,58 @@ def "escape-special-characters-and-quote escapes backslashes" [] { } # ============================================================================= -# Tests for check-print-append +# Tests for can-append-print # ============================================================================= @test -def "check-print-append returns true for simple commands" [] { - assert equal (check-print-append "ls") true - assert equal (check-print-append "echo hello") true +def "can-append-print returns true for simple commands" [] { + assert equal (can-append-print "ls") true + assert equal (can-append-print "echo hello") true } @test -def "check-print-append returns false for let statements" [] { - assert equal (check-print-append "let a = 1") false - assert equal (check-print-append "let a = ls") false +def "can-append-print returns false for let statements" [] { + assert equal (can-append-print "let a = 1") false + assert equal (can-append-print "let a = ls") false } @test -def "check-print-append returns false for mut statements" [] { - assert equal (check-print-append "mut a = 1") false +def "can-append-print returns false for mut statements" [] { + assert equal (can-append-print "mut a = 1") false } @test -def "check-print-append returns false for def statements" [] { - assert equal (check-print-append "def foo [] {}") false +def "can-append-print returns false for def statements" [] { + assert equal (can-append-print "def foo [] {}") false } @test -def "check-print-append returns false for semicolon ending" [] { - assert equal (check-print-append "ls;") false +def "can-append-print returns false for semicolon ending" [] { + assert equal (can-append-print "ls;") false } @test -def "check-print-append returns false for print ending" [] { - assert equal (check-print-append "ls | print") false +def "can-append-print returns false for print ending" [] { + assert equal (can-append-print "ls | print") false } @test -def "check-print-append returns false for source statements" [] { - assert equal (check-print-append "source a.nu") false - assert equal (check-print-append "overlay use foo") false - assert equal (check-print-append "alias ll = ls -la") false +def "can-append-print returns false for source statements" [] { + assert equal (can-append-print "source a.nu") false + assert equal (can-append-print "overlay use foo") false + assert equal (can-append-print "alias ll = ls -la") false } @test -def "check-print-append handles multi-statement commands" [] { +def "can-append-print handles multi-statement commands" [] { # Last span is echo - should be true - assert equal (check-print-append "source a.nu; echo abc") true + assert equal (can-append-print "source a.nu; echo abc") true # Last span is source - should be false - assert equal (check-print-append "echo abc; source a.nu") false + assert equal (can-append-print "echo abc; source a.nu") false # Multi-line: last is echo - assert equal (check-print-append "source a.nu\necho hello") true + assert equal (can-append-print "source a.nu\necho hello") true # Last span is use - should be false - assert equal (check-print-append "ls; use std") false + assert equal (can-append-print "ls; use std") false } # ============================================================================= @@ -331,33 +331,33 @@ def "get-last-span handles multi-line commands" [] { } # ============================================================================= -# Tests for modify-path +# Tests for build-modified-path # ============================================================================= @test -def "modify-path adds prefix" [] { - let result = "file.nu" | modify-path --prefix "test_" +def "build-modified-path adds prefix" [] { + let result = "file.nu" | build-modified-path --prefix "test_" assert equal $result "test_file.nu" } @test -def "modify-path adds suffix" [] { - let result = "file.nu" | modify-path --suffix "_backup" +def "build-modified-path adds suffix" [] { + let result = "file.nu" | build-modified-path --suffix "_backup" assert equal $result "file_backup.nu" } @test -def "modify-path changes extension" [] { - let result = "file.nu" | modify-path --extension ".md" +def "build-modified-path changes extension" [] { + let result = "file.nu" | build-modified-path --extension ".md" assert equal $result "file.nu.md" } @test -def "modify-path combines all options" [] { - let result = "file.nu" | modify-path --prefix "pre_" --suffix "_suf" --extension ".md" +def "build-modified-path combines all options" [] { + let result = "file.nu" | build-modified-path --prefix "pre_" --suffix "_suf" --extension ".md" assert equal $result "pre_file_suf.nu.md" } diff --git a/toolkit.nu b/toolkit.nu index 3dd9822..5dd197f 100644 --- a/toolkit.nu +++ b/toolkit.nu @@ -1,5 +1,5 @@ const numdinternals = ([numd commands.nu] | path join) -use $numdinternals [ modify-path ] +use $numdinternals [ build-modified-path ] export def main [] { } @@ -41,7 +41,7 @@ export def 'main testing-integration' [ # clear outputs from simple markdown ['z_examples' '1_simple_markdown' 'simple_markdown.md'] | path join - | numd clear-outputs $in -o ($in | modify-path --suffix '_with_no_output') + | numd clear-outputs $in -o ($in | build-modified-path --suffix '_with_no_output') # I use a long chain of `append` here to obtain a table with statistics on updates upon exit. @@ -72,13 +72,13 @@ export def 'main testing-integration' [ # Run file with customized width of table | append ( numd run $path_simple_table --no-backup --table-width 20 --result-md-path ( - $path_simple_table | modify-path --suffix '_customized_width20' + $path_simple_table | build-modified-path --suffix '_customized_width20' ) ) # Run file with another config | append ( numd run $path_simple_table --no-backup --config-path 'numd_config_example2.yaml' --result-md-path ( - $path_simple_table | modify-path --suffix '_customized_example_config' + $path_simple_table | build-modified-path --suffix '_customized_example_config' ) ) # Run readme diff --git a/z_examples/2_numd_commands_explanations/numd_commands_explanations.md b/z_examples/2_numd_commands_explanations/numd_commands_explanations.md index 1ef16ca..4620361 100644 --- a/z_examples/2_numd_commands_explanations/numd_commands_explanations.md +++ b/z_examples/2_numd_commands_explanations/numd_commands_explanations.md @@ -13,15 +13,15 @@ use ($init_numd_pwd_const | path join numd commands.nu) * ## numd-internals.nu -### find-code-blocks +### parse-markdown-to-blocks This command is used for parsing initial markdown to detect executable code blocks. ```nu # Here we set the `$file` variable (which will be used in several commands throughout this script) to point to `z_examples/1_simple_markdown/simple_markdown.md`. let $file = $init_numd_pwd_const | path join z_examples 1_simple_markdown simple_markdown.md -let $md_orig = open -r $file | toggle-output-fences -let $original_md_table = $md_orig | find-code-blocks +let $md_orig = open -r $file | convert-output-fences +let $original_md_table = $md_orig | parse-markdown-to-blocks $original_md_table | table -e --width 120 # => ╭─block_index─┬───────row_type───────┬───────────────────────────────────line────────────────────────────────────┬─act─╮ @@ -89,7 +89,7 @@ The `generate-intermediate-script` command generates a script that contains code ```nu # Here we emulate that the `$intermed_script_path` options is not set let $intermediate_script_path = $file - | modify-path --prefix $'numd-temp-(generate-timestamp)' --suffix '.nu' + | build-modified-path --prefix $'numd-temp-(generate-timestamp)' --suffix '.nu' decorate-original-code-blocks $original_md_table | generate-intermediate-script diff --git a/z_examples/2_numd_commands_explanations/numd_commands_explanations.md_intermed.nu b/z_examples/2_numd_commands_explanations/numd_commands_explanations.md_intermed.nu index 4fb182e..ab9690b 100644 --- a/z_examples/2_numd_commands_explanations/numd_commands_explanations.md_intermed.nu +++ b/z_examples/2_numd_commands_explanations/numd_commands_explanations.md_intermed.nu @@ -33,13 +33,13 @@ print '' ```nu" | print "# Here we set the `$file` variable (which will be used in several commands throughout this script) to point to `z_examples/1_simple_markdown/simple_markdown.md`. let $file = $init_numd_pwd_const | path join z_examples 1_simple_markdown simple_markdown.md -let $md_orig = open -r $file | toggle-output-fences -let $original_md_table = $md_orig | find-code-blocks" | nu-highlight | print +let $md_orig = open -r $file | convert-output-fences +let $original_md_table = $md_orig | parse-markdown-to-blocks" | nu-highlight | print # Here we set the `$file` variable (which will be used in several commands throughout this script) to point to `z_examples/1_simple_markdown/simple_markdown.md`. let $file = $init_numd_pwd_const | path join z_examples 1_simple_markdown simple_markdown.md -let $md_orig = open -r $file | toggle-output-fences -let $original_md_table = $md_orig | find-code-blocks +let $md_orig = open -r $file | convert-output-fences +let $original_md_table = $md_orig | parse-markdown-to-blocks print '' "$original_md_table | table -e --width 120" | nu-highlight | print @@ -51,11 +51,11 @@ print '' ```nu" | print "# Here we emulate that the `$intermed_script_path` options is not set let $intermediate_script_path = $file - | modify-path --prefix $'numd-temp-(generate-timestamp)' --suffix '.nu'" | nu-highlight | print + | build-modified-path --prefix $'numd-temp-(generate-timestamp)' --suffix '.nu'" | nu-highlight | print # Here we emulate that the `$intermed_script_path` options is not set let $intermediate_script_path = $file - | modify-path --prefix $'numd-temp-(generate-timestamp)' --suffix '.nu' + | build-modified-path --prefix $'numd-temp-(generate-timestamp)' --suffix '.nu' print '' "decorate-original-code-blocks $original_md_table | generate-intermediate-script diff --git a/z_examples/99_strip_markdown/numd_commands_explanations.nu b/z_examples/99_strip_markdown/numd_commands_explanations.nu index 484cb0b..a988975 100644 --- a/z_examples/99_strip_markdown/numd_commands_explanations.nu +++ b/z_examples/99_strip_markdown/numd_commands_explanations.nu @@ -11,8 +11,8 @@ use ($init_numd_pwd_const | path join numd commands.nu) * # ```nu # Here we set the `$file` variable (which will be used in several commands throughout this script) to point to `z_examples/1_simple_markdown/simple_markdown.md`. let $file = $init_numd_pwd_const | path join z_examples 1_simple_markdown simple_markdown.md -let $md_orig = open -r $file | toggle-output-fences -let $original_md_table = $md_orig | find-code-blocks +let $md_orig = open -r $file | convert-output-fences +let $original_md_table = $md_orig | parse-markdown-to-blocks $original_md_table | table -e --width 120 @@ -20,7 +20,7 @@ $original_md_table | table -e --width 120 # ```nu # Here we emulate that the `$intermed_script_path` options is not set let $intermediate_script_path = $file - | modify-path --prefix $'numd-temp-(generate-timestamp)' --suffix '.nu' + | build-modified-path --prefix $'numd-temp-(generate-timestamp)' --suffix '.nu' decorate-original-code-blocks $original_md_table | generate-intermediate-script From 9110b3dbbdd0b5d85c50f27b0256a24c83a497a3 Mon Sep 17 00:00:00 2001 From: maxim Date: Sat, 13 Dec 2025 16:50:01 -0300 Subject: [PATCH 11/12] refactor: rename commands for clarity --- numd/commands.nu | 26 +++++++++++++------------- tests/test_commands.nu | 10 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/numd/commands.nu b/numd/commands.nu index 9e20b61..e3b454c 100644 --- a/numd/commands.nu +++ b/numd/commands.nu @@ -317,9 +317,9 @@ export def classify-block-action [ } # Apply output formatting based on fence options (separate-block vs inline `# =>`). -def apply-output-formatting [fence_options: list]: string -> string { +def format-command-output [fence_options: list]: string -> string { if 'no-output' in $fence_options { return $in } else { } - | if 'separate-block' in $fence_options { create-fence-output } else { } + | if 'separate-block' in $fence_options { generate-separate-block-fence } else { } | if (can-append-print $in) { generate-inline-output-pipeline | generate-print-statement @@ -341,7 +341,7 @@ export def generate-block-execution [ | if 'try' in $fence_options { wrap-in-try-catch --new-instance=('new-instance' in $fence_options) } else { } - | apply-output-formatting $fence_options + | format-command-output $fence_options | $in + (char nl) # Always print a blank line after each command group to preserve visual separation | $in + "print ''" @@ -357,7 +357,7 @@ export def decorate-original-code-blocks [ | where action == 'execute' | insert code {|i| $i.line - | execute-block-lines ($i.row_type | extract-fence-options) + | process-code-block-content ($i.row_type | extract-fence-options) | generate-block-markers $i.block_index $i.row_type } } @@ -384,7 +384,7 @@ export def generate-intermediate-script []: table` output. -export def execute-block-lines [ +export def process-code-block-content [ fence_options: list # options from the code fence (e.g., 'no-output', 'try') ]: list -> list { skip | drop # skip code fences @@ -557,9 +557,9 @@ export def convert-short-options [ # Escape symbols to be printed unchanged inside a `print "something"` statement. # -# > 'abcd"dfdaf" "' | escape-special-characters-and-quote +# > 'abcd"dfdaf" "' | quote-for-print # "abcd\"dfdaf\" \"" -export def escape-special-characters-and-quote []: string -> string { +export def quote-for-print []: string -> string { # `to json` might give similar results, yet it replaces new lines # which spoils readability of intermediate scripts str replace --all --regex '(\\|\")' '\$1' @@ -606,7 +606,7 @@ export def code-block-marker [ # > 'ls' | generate-highlight-print # "ls" | nu-highlight | print export def generate-highlight-print []: string -> string { - escape-special-characters-and-quote + quote-for-print | $"($in) | nu-highlight | print(char nl)(char nl)" } @@ -724,7 +724,7 @@ export def wrap-in-try-catch [ --new-instance # execute in a separate Nushell instance to get formatted error messages ]: string -> string { if $new_instance { - escape-special-characters-and-quote + quote-for-print | ( $'($nu.current-exe) -c ($in)' + " | complete | if ($in.exit_code != 0) {get stderr} else {get stdout}" @@ -735,15 +735,15 @@ export def wrap-in-try-catch [ } # Generate a fenced code block for output with a specific format. -export def create-fence-output []: string -> string { +export def generate-separate-block-fence []: string -> string { # We use a combination of "\n" and (char nl) here for intermediate script formatting aesthetics $"\"```\\n```output-numd\" | print(char nl)(char nl)($in)" } # Join a list of strings and generate a print statement for the combined output. -export def generate-print-lines []: list -> string { +export def join-and-print []: list -> string { str join (char nl) - | escape-special-characters-and-quote + | quote-for-print | $'($in) | print' } @@ -756,7 +756,7 @@ export def generate-block-markers [ code-block-marker $block_number | append $fence - | generate-print-lines + | join-and-print | append $input | append '"```" | print' | append '' diff --git a/tests/test_commands.nu b/tests/test_commands.nu index ee9085c..89df087 100644 --- a/tests/test_commands.nu +++ b/tests/test_commands.nu @@ -237,19 +237,19 @@ def "convert-output-fences converts back" [] { } # ============================================================================= -# Tests for escape-special-characters-and-quote +# Tests for quote-for-print # ============================================================================= @test -def "escape-special-characters-and-quote escapes quotes" [] { - let result = 'hello "world"' | escape-special-characters-and-quote +def "quote-for-print escapes quotes" [] { + let result = 'hello "world"' | quote-for-print assert equal $result '"hello \"world\""' } @test -def "escape-special-characters-and-quote escapes backslashes" [] { - let result = 'path\to\file' | escape-special-characters-and-quote +def "quote-for-print escapes backslashes" [] { + let result = 'path\to\file' | quote-for-print assert equal $result '"path\\to\\file"' } From 91f4901d4c9b3e1bafbea7a597ff0bf0b752e88b Mon Sep 17 00:00:00 2001 From: claude Date: Sat, 13 Dec 2025 16:57:58 -0300 Subject: [PATCH 12/12] refactor: improve variable naming and flag clarity in commands.nu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renamed variables for better code readability: - convert-output-fences: a/b → expanded_format/compact_format - convert-output-fences: --back flag → --restore - get-last-span: s/f/len → start/end/offset Updated corresponding test to use new --restore flag name. --- numd/commands.nu | 28 ++++++++++++++-------------- tests/test_commands.nu | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/numd/commands.nu b/numd/commands.nu index e3b454c..893fa05 100644 --- a/numd/commands.nu +++ b/numd/commands.nu @@ -49,7 +49,7 @@ export def run [ let updated_md_ansi = merge-markdown $original_md_table $nu_res_with_block_index | clean-markdown - | convert-output-fences --back + | convert-output-fences --restore # if $save_intermed_script param wasn't set - remove the temporary intermediate script if $save_intermed_script == null { rm $intermediate_script_path } @@ -469,14 +469,14 @@ export def clean-markdown []: string -> string { # > "```nu\n123\n```\n\nOutput:\n\n```\n123" | convert-output-fences | to json # "```nu\n123\n```\n```output-numd\n123" export def convert-output-fences [ - a = "\n```\n\nOutput:\n\n```\n" # I set variables here to prevent collecting $in var - b = "\n```\n```output-numd\n" - --back + expanded_format = "\n```\n\nOutput:\n\n```\n" # default params to prevent collecting $in + compact_format = "\n```\n```output-numd\n" + --restore # convert back from compact to expanded format ]: string -> string { - if $back { - str replace --all $b $a + if $restore { + str replace --all $compact_format $expanded_format } else { - str replace --all $a $b + str replace --all $expanded_format $compact_format } } @@ -644,21 +644,21 @@ export def get-last-span [ | from json | to yaml | parse -r 'span:\n\s+start:(.*)\n\s+end:(.*)' - | rename s f - | into int s f + | rename start end + | into int start end # I just brute-forced AST filter parameters in nu 0.97, as `ast` awaits a better replacement or improvement. - let last_span_end = $spans.f | math max + let last_span_end = $spans.end | math max let longest_last_span_start = $spans - | where f == $last_span_end - | get s + | where end == $last_span_end + | get start | if ($in | length) == 1 { } else { sort | skip } | first - let len = $longest_last_span_start - $last_span_end + let offset = $longest_last_span_start - $last_span_end $command - | str substring $len.. + | str substring $offset.. } # Check if the command can have `| print` appended by analyzing its last span for semicolons or declaration keywords. diff --git a/tests/test_commands.nu b/tests/test_commands.nu index 89df087..b9827b7 100644 --- a/tests/test_commands.nu +++ b/tests/test_commands.nu @@ -228,9 +228,9 @@ def "convert-output-fences converts output format" [] { } @test -def "convert-output-fences converts back" [] { +def "convert-output-fences restores expanded format" [] { let input = "```nu\n123\n```\n```output-numd\n456\n```" - let result = $input | convert-output-fences --back + let result = $input | convert-output-fences --restore assert ($result =~ "Output:") assert ($result !~ "output-numd")