Skip to content

nushell-prophet/dotnu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

907 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

dotnu

dotnu - tools for Nushell module developers ๐Ÿ› ๏ธ

(A good companion for numd)

dotnu augments Nushell with helpers for literate programming, dependency analysis, and script profiling.

Video demo

dotnu demo

Quickstart

git

git clone https://github.com/nushell-prophet/dotnu; cd dotnu
use dotnu
nupm install https://github.com/nushell-prophet/dotnu --git
# if nupm modules are not in  `NU_LIB_DIRS`:
$env.NU_LIB_DIRS ++= [ ($env.NUPM_HOME | path join "modules") ]

use dotnu

Embeds โ€” Literate Programming

dotnu lets you write literate Nushell: ordinary Nushell scripts that include the real command output right after each pipeline ending in | print $in.

The | print $in suffix acts as a simple print in native Nushell and as a capture marker for dotnu, so scripts remain valid and functional even when run without loading the dotnu module.

dotnu embeds-update

Inserts captured output back into the script at capture points

The main command of the embeds family: takes a script, rewrites every print $in line so its output is easy to parse, runs the modified script, captures what each marked line prints, and then replaces the old # => blocks in the original file with the fresh output.

Run it on a file path (e.g., dotnu embeds-update dotnu-capture.nu) or pipe a script into it (e.g., "ls | print $in" | dotnu embeds-update).

dotnu embeds-update (file)    # `string -> nothing`, `string -> string`, `nothing -> string`, `nothing -> nothing`

Parameters:

  • file?: path

Flags:

  • --echo โ€” output updates to stdout

Helper commands

While it is easy to write scripts in an editor, there are several convenience helper commands that facilitate populating script files from the terminal.

dotnu embed-add

Embed stdin together with its command into the file

Captures only the pipeline you run it on โ€” useful for fine-grained examples.

dotnu embed-add

Flags:

  • --capture-path: path โ€” capture file to append to; remembered for later calls in the session
  • --pipe-further (-p) โ€” output input further to the pipeline
  • --published โ€” output the published representation into terminal
  • --dry-run

dotnu embeds-remove

Removes annotation lines starting with "# => " from the script

dotnu embeds-remove

Expand Code โ€” Generate Code from Directives

dotnu expand-code is the inverse of embeds-update. Where embeds-update runs code and writes its output back as # => comments, expand-code runs a pipeline written inside a comment and writes that pipeline's text result back as real code lines.

A directive is a line beginning with #**; everything after the marker is a Nushell pipeline that must return text. Each line of that text becomes one generated code line, inserted right after the directive and up to a #**end marker on its own line.

Start with an empty block โ€” here in a module's mod.nu, just the directive and its end marker:

#** ls *.nu | where name != 'mod.nu' | get name | each { $"export use ($in) *" } | to text
#**end

Running dotnu expand-code mod.nu fills the block, re-exporting every sibling command file:

#** ls *.nu | where name != 'mod.nu' | get name | each { $"export use ($in) *" } | to text
export use config.nu *
export use greet.nu *
export use history.nu *
#**end

The directive and the #**end marker are never modified, so a re-run replaces only the lines between them โ€” refreshing the generated code whenever the inputs change (here, whenever you add or remove a command file). Relative paths in the pipeline resolve against the file's own directory, so ls *.nu sees the module's own files.

Like embeds-update, you can run it on a file path (dotnu expand-code file.nu) or pipe a script in and get the result back ($script | dotnu expand-code). Pass --echo to print the result instead of saving to the file.

Dependency Analysis

dotnu dependencies

Check .nu module files to determine which commands depend on other commands.

dotnu dependencies ...(paths)

Parameters:

  • ...paths: path โ€” paths to nushell module files

Flags:

  • --keep-builtins โ€” keep builtin commands in the result page
  • --definitions-only โ€” output only commands' names definitions

Examples:

Analyze command dependencies in a module

dotnu dependencies ...(glob tests/assets/module-say/say/*.nu)
# => โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
# => โ”‚ # โ”‚  caller  โ”‚ filename_of_caller โ”‚  callee  โ”‚ step โ”‚
# => โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ค
# => โ”‚ 0 โ”‚ question โ”‚ ask.nu             โ”‚          โ”‚    0 โ”‚
# => โ”‚ 1 โ”‚ hello    โ”‚ hello.nu           โ”‚          โ”‚    0 โ”‚
# => โ”‚ 2 โ”‚ say      โ”‚ mod.nu             โ”‚ hello    โ”‚    0 โ”‚
# => โ”‚ 3 โ”‚ say      โ”‚ mod.nu             โ”‚ hi       โ”‚    0 โ”‚
# => โ”‚ 4 โ”‚ say      โ”‚ mod.nu             โ”‚ question โ”‚    0 โ”‚
# => โ”‚ 5 โ”‚ hi       โ”‚ mod.nu             โ”‚          โ”‚    0 โ”‚
# => โ”‚ 6 โ”‚ test-hi  โ”‚ test-hi.nu         โ”‚ hi       โ”‚    0 โ”‚
# => โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

dotnu filter-commands-with-no-tests

Filter commands after dotnu dependencies that aren't used by any test command. Test commands are detected by: name contains 'test' OR file matches 'test*.nu'

dotnu filter-commands-with-no-tests

Examples:

Find commands not covered by tests

dependencies ...(glob tests/assets/module-say/say/*.nu) | filter-commands-with-no-tests
# => โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
# => โ”‚ # โ”‚  caller  โ”‚ filename_of_caller โ”‚
# => โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
# => โ”‚ 0 โ”‚ question โ”‚ ask.nu             โ”‚
# => โ”‚ 1 โ”‚ hello    โ”‚ hello.nu           โ”‚
# => โ”‚ 2 โ”‚ say      โ”‚ mod.nu             โ”‚
# => โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Script Profiling

dotnu set-x

Open a regular .nu script. Divide it into blocks by "\n\n". Generate a new script that will print the code of each block before executing it, and print the timings of each block's execution.

dotnu set-x <file>

Parameters:

  • file: path โ€” path to .nu file

Flags:

  • --regex: string โ€” regex to split on blocks (default: '\n+\n' - blank lines)
  • --echo โ€” output script to terminal
  • --quiet โ€” don't print any messages

Examples:

Generate script with timing instrumentation

set-x tests/assets/set-x-demo.nu --echo | lines | first 3 | to text
# => mut $prev_ts = ( date now )
# => print ("> sleep 0.5sec" | nu-highlight)
# => sleep 0.5sec

Example with a simple script:

let $filename = [tests assets set-x-demo.nu] | path join
open $filename | lines | table -i false
# => โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
# => โ”‚ sleep 0.5sec โ”‚
# => โ”‚              โ”‚
# => โ”‚ sleep 0.7sec โ”‚
# => โ”‚              โ”‚
# => โ”‚ sleep 0.8sec โ”‚
# => โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
dotnu set-x $filename --echo | lines | table -i false
# => โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
# => โ”‚ mut $prev_ts = ( date now )                                                 โ”‚
# => โ”‚ print ("> sleep 0.5sec" | nu-highlight)                                     โ”‚
# => โ”‚ sleep 0.5sec                                                                โ”‚
# => โ”‚ print $'(ansi grey)((date now) - $prev_ts)(ansi reset)'; $prev_ts = (date   โ”‚
# => โ”‚ now);                                                                       โ”‚
# => โ”‚                                                                             โ”‚
# => โ”‚                                                                             โ”‚
# => โ”‚ print ("> sleep 0.7sec" | nu-highlight)                                     โ”‚
# => โ”‚ sleep 0.7sec                                                                โ”‚
# => โ”‚ print $'(ansi grey)((date now) - $prev_ts)(ansi reset)'; $prev_ts = (date   โ”‚
# => โ”‚ now);                                                                       โ”‚
# => โ”‚                                                                             โ”‚
# => โ”‚                                                                             โ”‚
# => โ”‚ print ("> sleep 0.8sec" | nu-highlight)                                     โ”‚
# => โ”‚ sleep 0.8sec                                                                โ”‚
# => โ”‚ print $'(ansi grey)((date now) - $prev_ts)(ansi reset)'; $prev_ts = (date   โ”‚
# => โ”‚ now);                                                                       โ”‚
# => โ”‚                                                                             โ”‚
# => โ”‚                                                                             โ”‚
# => โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Utilities

dotnu generate-numd

Generate .numd from .nu divided into blocks by "\n\n"

Pipe a .nu script into this command to convert it into .numd format (markdown with code blocks).

dotnu generate-numd
"sleep 0.5sec\n\nsleep 0.7sec" | dotnu generate-numd
# => ```nu
# => sleep 0.5sec
# => ```
# =>
# => ```nu
# => sleep 0.7sec
# => ```
# =>

dotnu extract-module-command

Extract a command with its whole dependency cascade from a module into one self-contained script. The module is imported into a clean nu -n process and command bodies are dumped via view source, so Nushell itself resolves export use chains, submodules and main renaming. Private dependencies are embedded as plain def, definitions come in dependency order, and imports of external modules (std etc.) are reproduced as use lines.

Importing a module runs its export-env blocks, so the command refuses modules containing export-env unless you pass --allow-export-env after inspecting them.

dotnu extract-module-command tests/assets/module-embed greet
# => use std/assert
# =>
# => export def greet-word [] {
# =>     assert true
# =>     'hello'
# => }
# =>
# => def subject [] { 'world' }
# =>
# => export def greet [] { $"(greet-word) (subject)!" }

Pass --vars (or a non-empty --set-vars) to turn the target into a debug scaffold instead: its parameters become let bindings you can edit, and its body is unwrapped to the top level, so sourcing the script runs the body with the variables in scope. The dependencies stay embedded as def. With --output, values you edit in the saved file are kept on re-extraction unless you pass --clear-vars.

dotnu extract-module-command tests/assets/module-embed greet-loud --vars
# => use std/assert
# =>
# => export def greet-word [] {
# =>     assert true
# =>     'hello'
# => }
# =>
# => def subject [] { 'world' }
# =>
# => # def greet-loud [ --upper ] {
# => #dotnu-vars-start
# => let $upper = false
# => #dotnu-vars-end
# =>     let msg = $"(greet-word) (subject)!"
# =>     if $upper { $msg | str upcase } else { $msg }

dotnu list-module-exports

List all exported definitions from a module file. Finds commands from export def and export use patterns, including bare and glob re-exports (resolved by reading the referenced submodule).

dotnu list-module-exports dotnu/mod.nu | first 5
# => โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
# => โ”‚ 0 โ”‚ dependencies    โ”‚
# => โ”‚ 1 โ”‚ embed-add       โ”‚
# => โ”‚ 2 โ”‚ embeds-remove   โ”‚
# => โ”‚ 3 โ”‚ embeds-update   โ”‚
# => โ”‚ 4 โ”‚ examples-update โ”‚
# => โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

dotnu list-module-interface

List module's callable interface - the main and main subcommand patterns that become available when you use the module.

dotnu list-module-interface tests/assets/b/example-mod1.nu
# => โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
# => โ”‚ 0 โ”‚ main โ”‚
# => โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

dotnu module-commands-code-to-record

Extract all commands from a module as a record of {command_name: source_code}

dotnu module-commands-code-to-record <module_path>

Parameters:

  • module_path: path โ€” path to a Nushell module file

About

dotnu - tools for Nushell module developers ๐Ÿ› ๏ธ

Topics

Resources

License

Stars

32 stars

Watchers

1 watching

Forks

Contributors