Skip to content
Open
549 changes: 529 additions & 20 deletions src/System.CommandLine.StaticCompletions/shells/NuShellShellProvider.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace System.CommandLine.StaticCompletions.Tests;

using System.CommandLine.Help;
using System.CommandLine.StaticCompletions.Shells;
using Xunit;
using Xunit.Abstractions;

public class NushellShellProviderTests(ITestOutputHelper log)
{
private IShellProvider _provider = new NushellShellProvider();

[Fact]
public async Task GenericCompletions()
{
await _provider.Verify(new("mycommand"), log);
}

[Fact]
public async Task SimpleOptionCompletion()
{
await _provider.Verify(new("mycommand")
{
new Option<string>("--name")
}, log);
}

[Fact]
public async Task SubcommandAndOptionInTopLevelList()
{
await _provider.Verify(new("mycommand")
{
new Option<string>("--name"),
new Command("subcommand")
}, log);
}

[Fact]
public async Task NestedSubcommandCompletion()
{
await _provider.Verify(new("mycommand")
{
new Command("subcommand")
{
new Command("nested")
}
}, log);
}

[Fact]
public async Task FlagOptionsHaveNoType()
{
await _provider.Verify(new("mycommand")
{
new Option<bool>("--verbose", "-v")
{
Arity = ArgumentArity.Zero
},
new Option<bool>("--debug")
{
Arity = ArgumentArity.Zero
}
}, log);
}

[Fact]
public async Task OptionWithAliasGenerated()
{
await _provider.Verify(new("mycommand")
{
new Option<string>("--configuration", "-c"),
new Option<int>("--verbosity", "-v")
}, log);
}

[Fact]
public async Task RecursiveOptionsInherited()
{
await _provider.Verify(new("mycommand")
{
new Option<bool>("--verbose", "-v")
{
Arity = ArgumentArity.Zero,
Recursive = true
},
new Command("subcommand")
{
new Option<string>("--name")
}
}, log);
}

[Fact]
public async Task RecursiveOptionsWithCompletions()
{
var verbosityOption = new Option<string>("--verbosity", "-v")
{
Recursive = true
};
verbosityOption.AcceptOnlyFromAmong("quiet", "minimal", "normal", "detailed", "diagnostic");

await _provider.Verify(new("mycommand")
{
verbosityOption,
new Command("subcommand")
{
new Option<string>("--name"),
new Command("nested")
}
}, log);
}

[Fact]
public async Task DynamicCompletionsGeneration()
{
var dynamicOption = new Option<string>("--project")
{
IsDynamic = true
};
var dynamicArg = new Argument<string>("file")
{
IsDynamic = true
};
Command command = new Command("mycommand")
{
dynamicOption,
dynamicArg
};
await _provider.Verify(command, log);
}

[Fact]
public async Task StaticCompletionsWithValues()
{
var optionWithCompletions = new Option<string>("--verbosity", "-v");
optionWithCompletions.AcceptOnlyFromAmong("quiet", "minimal", "normal", "detailed", "diagnostic");

await _provider.Verify(new("mycommand")
{
optionWithCompletions
}, log);
}

[Fact]
public async Task ArgumentWithCompletions()
{
var argWithCompletions = new Argument<string>("framework");
argWithCompletions.CompletionSources.Add((context) =>
{
return [
new("net6.0"),
new("net7.0"),
new("net8.0")
];
});

await _provider.Verify(new("mycommand")
{
argWithCompletions
}, log);
}

[Fact]
public async Task ComplexCommandHierarchy()
{
Command command = new Command("my-app")
{
new Option<bool>("-c")
{
Arity = ArgumentArity.Zero,
Recursive = true
},
new Option<bool>("-v")
{
Arity = ArgumentArity.Zero
},
new HelpOption(),
new Command("test", "Subcommand\nwith a second line")
{
new Option<bool>("--debug", "-d")
{
Arity = ArgumentArity.Zero
}
},
new Command("help", "Print this message or the help of the given subcommand(s)")
{
new Command("test")
}
};
await _provider.Verify(command, log);
}

[Fact]
public async Task TypeMappingForArguments()
{
await _provider.Verify(new("mycommand")
{
new Argument<FileInfo>("file"),
new Argument<DirectoryInfo>("directory"),
new Argument<int>("count"),
new Argument<double>("ratio")
}, log);
}

[Fact]
public async Task OptionalAndVariadicArguments()
{
await _provider.Verify(new("mycommand")
{
new Argument<string>("required"),
new Argument<string>("optional")
{
Arity = ArgumentArity.ZeroOrOne
},
new Argument<string[]>("files")
{
Arity = ArgumentArity.ZeroOrMore
}
}, log);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Static completion definitions for mycommand.
# Generated by `dotnet completions script nushell`.

# Place this file in one of the paths listed in $env.NU_LIB_DIRS
# then `use` it in your config.nu or elsewhere.

# For example, if ~/.config/nushell/lib is in your $env.NU_LIB_DIRS,
# you could place this file as `dotnet-completions.nu` in the above
# directory and then put the following line in your config.nu:
# `use dotnet-completions.nu *`

# Of course, the above assumes that your $env.NU_LIB_DIRS is
# actually populated; refer to
# <https://www.nushell.sh/book/configuration.html> if it isn't.

# Alternatively, you can put this file wherever you want and `use`
# the absolute path to the file:
# `use /path/to/this/file.nu *`

export extern "mycommand" [
framework: string@["net6.0" "net7.0" "net8.0"]
]

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Static completion definitions for my-app.
# Generated by `dotnet completions script nushell`.

# Place this file in one of the paths listed in $env.NU_LIB_DIRS
# then `use` it in your config.nu or elsewhere.

# For example, if ~/.config/nushell/lib is in your $env.NU_LIB_DIRS,
# you could place this file as `dotnet-completions.nu` in the above
# directory and then put the following line in your config.nu:
# `use dotnet-completions.nu *`

# Of course, the above assumes that your $env.NU_LIB_DIRS is
# actually populated; refer to
# <https://www.nushell.sh/book/configuration.html> if it isn't.

# Alternatively, you can put this file wherever you want and `use`
# the absolute path to the file:
# `use /path/to/this/file.nu *`

export extern "my-app" [
--c
--v
]

# Subcommand
export extern "my-app test" [
--debug(-d)
--c
]

# Print this message or the help of the given subcommand(s)
export extern "my-app help" [
--c
]

export extern "my-app help test" [
--c
]

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Static completion definitions for mycommand.
# Generated by `dotnet completions script nushell`.

# Place this file in one of the paths listed in $env.NU_LIB_DIRS
# then `use` it in your config.nu or elsewhere.

# For example, if ~/.config/nushell/lib is in your $env.NU_LIB_DIRS,
# you could place this file as `dotnet-completions.nu` in the above
# directory and then put the following line in your config.nu:
# `use dotnet-completions.nu *`

# Of course, the above assumes that your $env.NU_LIB_DIRS is
# actually populated; refer to
# <https://www.nushell.sh/book/configuration.html> if it isn't.

# Alternatively, you can put this file wherever you want and `use`
# the absolute path to the file:
# `use /path/to/this/file.nu *`

# Dynamic completion function
def "nu-complete mycommand-dynamic" [context: string] {
^mycommand complete --position ($context | str length) $context | lines
}

export extern "mycommand" [
file: string@"nu-complete mycommand-dynamic"
--project: string@"nu-complete mycommand-dynamic"
]

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Static completion definitions for mycommand.
# Generated by `dotnet completions script nushell`.

# Place this file in one of the paths listed in $env.NU_LIB_DIRS
# then `use` it in your config.nu or elsewhere.

# For example, if ~/.config/nushell/lib is in your $env.NU_LIB_DIRS,
# you could place this file as `dotnet-completions.nu` in the above
# directory and then put the following line in your config.nu:
# `use dotnet-completions.nu *`

# Of course, the above assumes that your $env.NU_LIB_DIRS is
# actually populated; refer to
# <https://www.nushell.sh/book/configuration.html> if it isn't.

# Alternatively, you can put this file wherever you want and `use`
# the absolute path to the file:
# `use /path/to/this/file.nu *`

export extern "mycommand" [
--verbose(-v)
--debug
]

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Static completion definitions for mycommand.
# Generated by `dotnet completions script nushell`.

# Place this file in one of the paths listed in $env.NU_LIB_DIRS
# then `use` it in your config.nu or elsewhere.

# For example, if ~/.config/nushell/lib is in your $env.NU_LIB_DIRS,
# you could place this file as `dotnet-completions.nu` in the above
# directory and then put the following line in your config.nu:
# `use dotnet-completions.nu *`

# Of course, the above assumes that your $env.NU_LIB_DIRS is
# actually populated; refer to
# <https://www.nushell.sh/book/configuration.html> if it isn't.

# Alternatively, you can put this file wherever you want and `use`
# the absolute path to the file:
# `use /path/to/this/file.nu *`

export extern "mycommand" [
]

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Static completion definitions for mycommand.
# Generated by `dotnet completions script nushell`.

# Place this file in one of the paths listed in $env.NU_LIB_DIRS
# then `use` it in your config.nu or elsewhere.

# For example, if ~/.config/nushell/lib is in your $env.NU_LIB_DIRS,
# you could place this file as `dotnet-completions.nu` in the above
# directory and then put the following line in your config.nu:
# `use dotnet-completions.nu *`

# Of course, the above assumes that your $env.NU_LIB_DIRS is
# actually populated; refer to
# <https://www.nushell.sh/book/configuration.html> if it isn't.

# Alternatively, you can put this file wherever you want and `use`
# the absolute path to the file:
# `use /path/to/this/file.nu *`

export extern "mycommand" [
]

export extern "mycommand subcommand" [
]

export extern "mycommand subcommand nested" [
]

Loading