diff --git a/mod.nu b/mod.nu new file mode 100644 index 0000000..fde917c --- /dev/null +++ b/mod.nu @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright (c) 2026 MatrixFurry + +const template: path = path self ./template.nu + +export def install [ + src: path # Module source path + prefix?: path = ~/.local # installation prefix + --force (-f) # Overwrite existing files + --install-module (-i) # Install module in Nushell library directory + --bin-name (-b): string # Override final binary name + --module-name (-m): string # Override module name + --print-usage # [EXPERIMENTAL] Print command usage when executing --help or --list +] { + let src = $src | path expand + let prefix = $prefix | path expand + let mod_name = $module_name | default ($src | path basename) + let installed_mod_path = $prefix | path join "share" $mod_name "module" $mod_name + let bin_name = $bin_name | default $mod_name + let installed_bin_path = $prefix | path join "bin" $bin_name + + if $force { + rm -rf $installed_mod_path + rm -f $installed_bin_path + } else if ($installed_mod_path | path exists) or ($installed_bin_path | path exists) { + error make -u { + msg: "It looks like this tool is already installed, or there are conflicting files installed" + help: "If you're attempting to update or re-install the tool, use --force" + } + } + + # Module + mkdir ($installed_mod_path | path dirname) + cp -r $src $installed_mod_path + + if $install_module { + let nu_lib_dir = $NU_LIB_DIRS | first + if $force {rm -f ($nu_lib_dir | path join $mod_name)} + ln -s $installed_mod_path $nu_lib_dir + } + + # Create & install binary + mkdir ($installed_bin_path | path dirname) + + open $template --raw + | str replace "@MODULE_PATH@" $installed_mod_path + | str replace "@PRINT_USAGE@" ($print_usage | into string) + | save --progress $installed_bin_path + + chmod +x $installed_bin_path +} + +export def uninstall [ + name: string # CLI tool to uninstall + prefix?: path = ~/.local # installation prefix + --bin-name (-b): string # Override binary name + --remove-module (-m) # Remove module in Nushell library directory +] { + let prefix = $prefix | path expand + let mod_name = $name + let installed_mod_path = $prefix | path join "share" $mod_name "module" $mod_name + let bin_name = $bin_name | default $name + let installed_bin_path = $prefix | path join "bin" $bin_name + + rm -rf $installed_mod_path + rm -f $installed_bin_path + + if $remove_module { + let nu_lib_dir = $NU_LIB_DIRS | first + rm -f ($nu_lib_dir | path join $mod_name) + } +} + diff --git a/template.nu b/template.nu new file mode 100644 index 0000000..a784bfe --- /dev/null +++ b/template.nu @@ -0,0 +1,72 @@ +#!/usr/bin/env nu +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright (c) 2026 MatrixFurry + +const module_path = @MODULE_PATH@ +const module_name = $module_path | path basename +const print_usage = @PRINT_USAGE@ + +use std log +use $module_path + +def main --wrapped [ + # TODO: --choose (-c) # Interactively choose a function + --help (-h) + --list (-l) # List available commands + --interactive (-i) # Enter interactive shell with the module loaded + ...cmd +] { + if $interactive { + exec nu -e $"use ($module_path); print '(ansi yellow)Module loaded.(ansi reset)'" + } else if $help or $list or ($cmd | length) == 0 { + print-functions + } else { + let cmd_str = $cmd | str join ' ' + let function = get-functions | where $it starts-with $cmd_str | first + + if ($function | is-empty) { + log error $"Unknown command: `($cmd_str)`" + print-functions + } + + exec nu -c $"use ($module_path); ($module_name) ($cmd_str)" + } +} + +def get-functions [] { + scope modules + | where name == $module_name + | get 0.commands.name +} + +def print-functions [] { + get-functions + | where not ($it starts-with "_") + | each {|function| + let usage = if $print_usage { + let help = help $module_name $function | lines + {( + $help + | get ( + ($help | enumerate | where item == $"(ansi green)Usage(ansi reset):").0.index + 1 + ) + | str trim + )} + } else {{}} + + let short_description = $help + | first + | if $in == $"(ansi green)Usage(ansi reset):" { + null + } else { + $in + } + + { + command: $"(ansi cyan)($function)(ansi reset)" + description: $"(ansi lp)($short_description)(ansi reset)" + } merge $usage + } + | table --index false --theme rounded +} +