TeamCity.CSharpInteractive/Info.cs (192 lines of code) (raw):

// ReSharper disable ClassNeverInstantiated.Global namespace TeamCity.CSharpInteractive; using System.Diagnostics.CodeAnalysis; using System.Reflection; using HostApi; using Microsoft.CodeAnalysis.CSharp; [ExcludeFromCodeCoverage] internal class Info : IInfo { private readonly string _description; private readonly string _version; private readonly IStdOut _stdOut; private readonly ISettings _settings; private readonly IPresenter<IEnumerable<ITraceSource>> _tracePresenter; private readonly IEnumerable<ITraceSource> _traceSources; private readonly IEnumerable<ISettingDescription> _settingDescriptions; public Info( Assembly? assembly, LanguageVersion languageVersion, IStdOut stdOut, ISettings settings, IPresenter<IEnumerable<ITraceSource>> tracePresenter, IEnumerable<ITraceSource> traceSources, IEnumerable<ISettingDescription> settingDescriptions) { _description = string.Format(assembly?.GetCustomAttribute<AssemblyDescriptionAttribute>()?.Description ?? "C# {0} script runner", languageVersion.ToDisplayString()); _version = assembly?.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? string.Empty; _stdOut = stdOut; _settings = settings; _tracePresenter = tracePresenter; _traceSources = traceSources; _settingDescriptions = settingDescriptions; } public void ShowHeader() { _stdOut.WriteLine(new Text(_description, Color.Header)); if (_settings.InteractionMode != InteractionMode.Interactive) { return; } _stdOut.WriteLine(new Text("Ctrl-C - Exit the REPL.", Color.Highlighted)); _stdOut.WriteLine(new Text("#help - Display help on available commands and key bindings.", Color.Highlighted)); } public void ShowReplHelp() { var lines = new List<Text> { new("Keyboard shortcuts:", Color.Header), Text.NewLine, Text.Tab, new("Enter ", Color.Header), new("If the current submission appears to be complete, evaluate it. Otherwise, insert a new line."), Text.NewLine, Text.Tab, new("Escape ", Color.Header), new("Clear the current submission."), Text.NewLine, Text.Tab, new("UpArrow ", Color.Header), new("Replace the current submission with a previous submission."), Text.NewLine, Text.Tab, new("DownArrow ", Color.Header), new("Replace the current submission with a subsequent submission (after having previously navigated backwards)."), Text.NewLine, Text.Tab, new("Ctrl-C ", Color.Header), new("Exit the REPL."), Text.NewLine, new("REPL commands:", Color.Header), Text.NewLine, Text.Tab, new("#help ", Color.Header), new("Display help on available commands and key bindings."), Text.NewLine }; var settingLines = from setting in _settingDescriptions where setting.IsVisible select new[] { Text.Tab, new Text($"#{setting.Key,-12}", Color.Header), new Text($"{setting.Description} {string.Join(", ", Enum.GetValues(setting.SettingType).OfType<Enum>().Select(i => i.ToString()))}, e.g. "), new Text($"#{setting.Key} {Enum.GetValues(setting.SettingType).OfType<Enum>().LastOrDefault()}", Color.Highlighted), new Text("."), Text.NewLine }; lines.AddRange(settingLines.SelectMany(i => i)); lines.AddRange(new[] { new Text("Script directives:", Color.Header), Text.NewLine, Text.Tab, new Text("#r ", Color.Header), new Text("Add a reference to a NuGet package or specified assembly and all its dependencies, e.g., "), new Text("#r \"nuget:MyPackage, 1.2.3\"", Color.Highlighted), new Text(" or "), new Text("#r \"nuget:MyPackage\"", Color.Highlighted), new Text(" or "), new Text("#r \"MyLib.dll\"", Color.Highlighted), new Text("."), Text.NewLine, Text.Tab, new Text("#load ", Color.Header), new Text("Load specified script file and execute it, e.g. "), new Text("#load \"script-file.csx\"", Color.Highlighted), new Text(".") }); _stdOut.WriteLine(lines.ToArray()); } public void ShowHelp() => _stdOut.WriteLine( new [] { new[] { Text.NewLine, new("Usage:", Color.Header), new(" dotnet csi [options] [--] [script] [script arguments]"), Text.NewLine, Text.NewLine, new("Executes a script if specified, otherwise launches an interactive REPL (Read Eval Print Loop)."), Text.NewLine, Text.NewLine }, Option( "script", new Text("The path to the script file to run."), Text.NewLine, Text.Tab, new Text("If no such file is found, the command will treat it as a directory"), Text.NewLine, Text.Tab, new Text("and look for a single script file inside that directory.")), Option( "script arguments", new Text("Script arguments are accessible in a script via the global list "), new Text("Args[index]", Color.Details), new Text(" by an argument index.")), Option("--", new Text("Indicates that the remaining arguments should not be treated as options.")), Option( "--help", new Text("Display this usage message (alternative forms: /? -h /h /help).")), Option("--version", new Text("Display the version and exit (alternative form: /version).")), Option("--source <NuGet package source>", new Text("NuGet package source (URL, UNC/folder path) to use (alternative forms: -s /source /s),"), Text.NewLine, Text.Tab, new Text("for example: "), new Text("--source https://api.nuget.org/v3/index.json", Color.Details)), Option("--property <key=value>[;<keyN=valueN>]", new Text("Define a key-value pair(s) for the script properties "), new Text("(*1)", Color.Highlighted), new Text(" accessible in scripts."), Text.NewLine, Text.Tab, new Text("Alternative forms:"), Text.NewLine, Text.Tab, Text.Tab, new Text("-property"), Text.NewLine, Text.Tab, Text.Tab, new Text("-p"), Text.NewLine, Text.Tab, Text.Tab, new Text("/property"), Text.NewLine, Text.Tab, Text.Tab, new Text("/p"), Text.NewLine, Text.Tab, new Text("Specify each property separately, or use a semicolon or comma to separate multiple properties,"), Text.NewLine, Text.Tab, new Text("as the following example shows: "), new Text("--property key1=val1;key2=val2", Color.Details)), Option("--property:<key=value>[;<keyN=valueN>]", new Text("Define a key-value pair(s) in MSBuild style for the script properties "), new Text("(*1)", Color.Highlighted), new Text(" accessible in scripts."), Text.NewLine, Text.Tab, new Text("Alternative forms:"), Text.NewLine, Text.Tab, Text.Tab, new Text("-property:<key=value>"), Text.NewLine, Text.Tab, Text.Tab, new Text("-p:<key=value>"), Text.NewLine, Text.Tab, Text.Tab, new Text("/property:<key=value>"), Text.NewLine, Text.Tab, Text.Tab, new Text("/p:<key=value>"), Text.NewLine, Text.Tab, new Text("Specify each property separately, or use a semicolon or comma to separate multiple properties,"), Text.NewLine, Text.Tab, new Text("as the following example shows: "), new Text("--property:key1=val1;key2=val2", Color.Details)), Option("@<file>", new Text("Read response file for more options as the following example shows: "), new Text("@OptionsDir/MyOptions.rsp", Color.Details)), new[] { new("Notes:", Color.Header), Text.NewLine, Text.Tab, new("- "), new("*1", Color.Highlighted), new(" script properties are accessible a script via the global dictionary "), new("Props[\"name\"]", Color.Details), new(" by a property name"), Text.NewLine, Text.Tab, new("- "), new("using HostApi;", Color.Details), new Text(" directive in a script allows you to use host API types"), Text.NewLine, Text.Tab, new Text(" without specifying the fully qualified namespace of these types") } }.SelectMany(i => i).ToArray() ); public void ShowVersion() => _stdOut.WriteLine(new Text(_version)); public void ShowFooter() => _tracePresenter.Show(_traceSources); private static Text[] Option(string option, params Text[] description) { return new [] { new [] { new Text(option, Color.Header), Text.NewLine, Text.Tab }, description, new [] { Text.NewLine, Text.NewLine, } }.SelectMany(i => i).ToArray(); } }