Skip to content

Commit

Permalink
[CLI] Open help in web browser (dotnet#1179)
Browse files Browse the repository at this point in the history
  • Loading branch information
josefpihrt authored and JochemHarmes committed Oct 30, 2023
1 parent 4f0858b commit 8880400
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 101 deletions.
4 changes: 4 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Remove empty region directive ([RCS1091](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1091))
- Remove empty destructor ([RCS1106](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1106))

### Changed

- [CLI] Open help in web browser when running command `roslynator help <COMMAND>` ([#1179](https://github.com/josefpihrt/roslynator/pull/1179))

### Fixed

- Fix [RCS1187](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1187) ([#1150](https://github.com/JosefPihrt/Roslynator/pull/1150)).
Expand Down
163 changes: 70 additions & 93 deletions src/CommandLine/Commands/HelpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,45 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Roslynator.CommandLine.Help;
using static Roslynator.Logger;

namespace Roslynator.CommandLine;

internal class HelpCommand
{
public HelpCommand(HelpCommandLineOptions options, Filter filter)
public HelpCommand(HelpCommandLineOptions options)
{
Options = options;
Filter = filter;
}

public HelpCommandLineOptions Options { get; }

public Filter Filter { get; }

public CommandStatus Execute()
{
try
{
WriteHelp(
commandName: Options.Command,
online: false,
manual: Options.Manual,
includeValues: ConsoleOut.Verbosity > Verbosity.Normal,
filter: Filter);
if (Options.Manual)
{
WriteManual();
}
else if (Options.Command is not null)
{
Command command = CommandLoader.LoadCommand(typeof(HelpCommand).Assembly, Options.Command);

if (command is null)
throw new InvalidOperationException($"Command '{Options.Command}' does not exist.");

OpenHelpInBrowser(Options.Command);
}
else
{
WriteCommandsHelp();
}

return CommandStatus.Success;
}
Expand All @@ -42,136 +52,103 @@ public CommandStatus Execute()
}
}

private static void WriteHelp(
string commandName,
bool online,
bool manual,
bool includeValues,
Filter filter = null)
private static void OpenHelpInBrowser(string commandName)
{
if (online)
{
OpenHelpInBrowser(commandName);
}
else if (commandName is not null)
{
Command command = CommandLoader.LoadCommand(typeof(HelpCommand).Assembly, commandName);
var url = "https://josefpihrt.github.io/docs/roslynator/cli";

if (command is null)
throw new InvalidOperationException($"Command '{commandName}' does not exist.");
if (commandName is not null)
url += $"/commands/{commandName}";

WriteCommandHelp(command, includeValues: includeValues, filter: filter);
}
else if (manual)
try
{
WriteManual(includeValues: includeValues, filter: filter);
Process.Start(url);
}
else
catch
{
WriteCommandsHelp(includeValues: includeValues, filter: filter);
}
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var psi = new ProcessStartInfo()
{
FileName = url,
UseShellExecute = true
};

[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter")]
private static void OpenHelpInBrowser(string commandName)
{
throw new NotSupportedException();
Process.Start(psi);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Process.Start("xdg-open", url);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", url);
}
else
{
throw;
}
}
}

public static void WriteCommandHelp(Command command, bool includeValues = false, Filter filter = null)
public static void WriteCommandHelp(Command command)
{
var writer = new ConsoleHelpWriter(new HelpWriterOptions(filter: filter));
var writer = new ConsoleHelpWriter();

command = command.WithOptions(command.Options.Sort(CommandOptionComparer.Name));

CommandHelp commandHelp = CommandHelp.Create(command, providers: null, filter: filter);
CommandHelp commandHelp = CommandHelp.Create(command);

writer.WriteCommand(commandHelp);

if (includeValues)
writer.WriteValues(commandHelp.Values);
}

public static void WriteCommandsHelp(bool includeValues = false, Filter filter = null)
public static void WriteCommandsHelp()
{
IEnumerable<Command> commands = LoadCommands().Where(f => f.Name != "help");

CommandsHelp commandsHelp = CommandsHelp.Create(commands, providers: null, filter: filter);
CommandsHelp commandsHelp = CommandsHelp.Create(commands);

var writer = new ConsoleHelpWriter(new HelpWriterOptions(filter: filter));
var writer = new ConsoleHelpWriter(new HelpWriterOptions());

writer.WriteCommands(commandsHelp);

if (includeValues)
writer.WriteValues(commandsHelp.Values);

WriteLine();
WriteLine(GetFooterText());
}

private static void WriteManual(bool includeValues = false, Filter filter = null)
private static void WriteManual()
{
IEnumerable<Command> commands = LoadCommands();

var writer = new ConsoleHelpWriter(new HelpWriterOptions(filter: filter));
var writer = new ConsoleHelpWriter();

IEnumerable<CommandHelp> commandHelps = commands.Select(f => CommandHelp.Create(f, filter: filter))
IEnumerable<CommandHelp> commandHelps = commands.Select(f => CommandHelp.Create(f))
.Where(f => f.Arguments.Any() || f.Options.Any())
.ToImmutableArray();

ImmutableArray<CommandItem> commandItems = HelpProvider.GetCommandItems(commandHelps.Select(f => f.Command));

ImmutableArray<OptionValueList> values = ImmutableArray<OptionValueList>.Empty;
var commandsHelp = new CommandsHelp(commandItems, ImmutableArray<OptionValueList>.Empty);

if (commandItems.Any())
{
values = HelpProvider.GetOptionValues(
commandHelps.SelectMany(f => f.Command.Options),
providers: ImmutableArray<OptionValueProvider>.Empty,
filter);
writer.WriteCommands(commandsHelp);

var commandsHelp = new CommandsHelp(commandItems, values);
foreach (CommandHelp commandHelp in commandHelps)
{
WriteSeparator();
WriteLine();
WriteLine($"Command: {commandHelp.Name}");
WriteLine();

writer.WriteCommands(commandsHelp);
string description = commandHelp.Description;

foreach (CommandHelp commandHelp in commandHelps)
if (!string.IsNullOrEmpty(description))
{
WriteSeparator();
WriteLine(description);
WriteLine();
WriteLine($"Command: {commandHelp.Name}");
WriteLine();

string description = commandHelp.Description;

if (!string.IsNullOrEmpty(description))
{
WriteLine(description);
WriteLine();
}

writer.WriteCommand(commandHelp);
}

if (includeValues)
WriteSeparator();
}
else
{
WriteLine();
WriteLine("No command found");

if (includeValues)
{
values = HelpProvider.GetOptionValues(
commands.Select(f => CommandHelp.Create(f)).SelectMany(f => f.Command.Options),
providers: ImmutableArray<OptionValueProvider>.Empty,
filter);
}
writer.WriteCommand(commandHelp);
}

if (includeValues)
writer.WriteValues(values);

static void WriteSeparator()
{
WriteLine();
Expand Down
1 change: 0 additions & 1 deletion src/CommandLine/OptionShortNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ internal static class OptionShortNames
{
public const char AnalyzerAssemblies = 'a';
public const char DryRun = 'd';
public const char Filter = 'f';
public const char IncludeGeneratedCode = 'g';
public const char Help = 'h';
public const char Manual = 'm';
Expand Down
8 changes: 1 addition & 7 deletions src/CommandLine/Options/HelpCommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@ internal sealed class HelpCommandLineOptions : AbstractCommandLineOptions
HelpText = "Command name.",
MetaName = "<COMMAND>")]
public string Command { get; set; } = null!;
#if DEBUG
[Option(
shortName: OptionShortNames.Filter,
longName: "filter",
HelpText = "Search phrase to filter the results.")]
public string Filter { get; set; }
#endif

[Option(
shortName: OptionShortNames.Manual,
longName: "manual",
Expand Down

0 comments on commit 8880400

Please sign in to comment.