| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782 |
- using System.Collections.ObjectModel;
- using System.Diagnostics;
- using System.Runtime.InteropServices;
- using System.Text;
- using System.Text.Json.Serialization;
- using Microsoft.Extensions.Logging;
- using RuntimeEnvironment = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment;
- #nullable enable
- namespace UICatalog;
- /// <summary>
- /// This is the main UI Catalog app view. It is run fresh when the app loads (if a Scenario has not been passed on
- /// the command line) and each time a Scenario ends.
- /// </summary>
- public class UICatalogRunnable : Runnable
- {
- // When a scenario is run, the main app is killed. The static
- // members are cached so that when the scenario exits the
- // main app UI can be restored to previous state
- // Note, we used to pass this to scenarios that run, but it just added complexity
- // So that was removed. But we still have this here to demonstrate how changing
- // the scheme works.
- public static string? CachedRunnableScheme { get; set; }
- // Diagnostics
- private static ViewDiagnosticFlags _diagnosticFlags;
- public UICatalogRunnable ()
- {
- _diagnosticFlags = Diagnostics;
- _menuBar = CreateMenuBar ();
- _statusBar = CreateStatusBar ();
- _categoryList = CreateCategoryList ();
- _scenarioList = CreateScenarioList ();
- Add (_menuBar, _categoryList, _scenarioList, _statusBar);
- IsModalChanged += IsModalChangedHandler;
- IsRunningChanged += IsRunningChangedHandler;
- // Restore previous selections
- if (_categoryList.Source?.Count > 0)
- {
- _categoryList.SelectedItem = _cachedCategoryIndex ?? 0;
- }
- else
- {
- _categoryList.SelectedItem = null;
- }
- _scenarioList.SelectedRow = _cachedScenarioIndex;
- SchemeName = CachedRunnableScheme = SchemeManager.SchemesToSchemeName (Schemes.Base);
- ConfigurationManager.Applied += ConfigAppliedHandler;
- }
- private static bool _isFirstRunning = true;
- private void IsModalChangedHandler (object? sender, EventArgs<bool> args)
- {
- if (!args.Value)
- {
- return;
- }
- if (_disableMouseCb is { })
- {
- _disableMouseCb.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked;
- }
- if (_shVersion is { })
- {
- _shVersion.Title = $"{RuntimeEnvironment.OperatingSystem} {RuntimeEnvironment.OperatingSystemVersion}, {Application.Driver!.GetVersionInfo ()}";
- }
- if (CachedSelectedScenario != null)
- {
- CachedSelectedScenario = null;
- _isFirstRunning = false;
- }
- if (!_isFirstRunning)
- {
- _scenarioList.SetFocus ();
- }
- if (_statusBar is { })
- {
- _statusBar.VisibleChanged += (s, e) => { ShowStatusBar = _statusBar.Visible; };
- }
- IsModalChanged -= IsModalChangedHandler;
- _categoryList!.EnsureSelectedItemVisible ();
- _scenarioList.EnsureSelectedCellIsVisible ();
- }
- private void IsRunningChangedHandler (object? sender, EventArgs<bool> args)
- {
- if (!args.Value)
- {
- ConfigurationManager.Applied -= ConfigAppliedHandler;
- IsRunningChanged -= IsRunningChangedHandler;
- }
- }
- #region MenuBar
- private readonly MenuBar? _menuBar;
- private CheckBox? _force16ColorsMenuItemCb;
- private OptionSelector? _themesSelector;
- private OptionSelector? _topSchemesSelector;
- private OptionSelector? _logLevelSelector;
- private FlagSelector<ViewDiagnosticFlags>? _diagnosticFlagsSelector;
- private CheckBox? _disableMouseCb;
- private MenuBar CreateMenuBar ()
- {
- MenuBar menuBar = new (
- [
- new (
- "_File",
- [
- new MenuItem ()
- {
- Title ="_Quit",
- HelpText = "Quit UI Catalog",
- Key = Application.QuitKey,
- // By not specifying TargetView the Key Binding will be Application-level
- Command = Command.Quit
- }
- ]),
- new ("_Themes", CreateThemeMenuItems ()),
- new ("Diag_nostics", CreateDiagnosticMenuItems ()),
- new ("_Logging", CreateLoggingMenuItems ()),
- new (
- "_Help",
- [
- new MenuItem (
- "_Documentation",
- "API docs",
- () => OpenUrl ("https://gui-cs.github.io/Terminal.Gui"),
- Key.F1
- ),
- new MenuItem (
- "_README",
- "Project readme",
- () => OpenUrl ("https://github.com/gui-cs/Terminal.Gui"),
- Key.F2
- ),
- new MenuItem (
- "_About...",
- "About UI Catalog",
- () => MessageBox.Query (
- App,
- "",
- GetAboutBoxMessage (),
- wrapMessage: false,
- buttons: "_Ok"
- ),
- Key.A.WithCtrl
- )
- ])
- ])
- {
- Title = "menuBar",
- Id = "menuBar"
- };
- return menuBar;
- View [] CreateThemeMenuItems ()
- {
- List<View> menuItems = [];
- _force16ColorsMenuItemCb = new ()
- {
- Title = "Force _16 Colors",
- CheckedState = Application.Driver!.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
- // Best practice for CheckBoxes in menus is to disable focus and highlight states
- CanFocus = false,
- HighlightStates = MouseState.None
- };
- _force16ColorsMenuItemCb.CheckedStateChanging += (sender, args) =>
- {
- if (Application.Driver!.Force16Colors
- && args.Result == CheckState.UnChecked
- && !Application.Driver!.SupportsTrueColor)
- {
- args.Handled = true;
- }
- };
- _force16ColorsMenuItemCb.CheckedStateChanged += (sender, args) =>
- {
- Application.Driver!.Force16Colors = args.Value == CheckState.Checked;
- _force16ColorsShortcutCb!.CheckedState = args.Value;
- SetNeedsDraw ();
- };
- menuItems.Add (
- new MenuItem
- {
- CommandView = _force16ColorsMenuItemCb
- });
- menuItems.Add (new Line ());
- if (ConfigurationManager.IsEnabled)
- {
- _themesSelector = new ()
- {
- // HighlightStates = MouseState.In,
- CanFocus = true,
- // InvertFocusAttribute = true
- };
- _themesSelector.ValueChanged += (_, args) =>
- {
- if (args.Value is null)
- {
- return;
- }
- ThemeManager.Theme = ThemeManager.GetThemeNames () [(int)args.Value];
- };
- var menuItem = new MenuItem
- {
- CommandView = _themesSelector,
- HelpText = "Cycle Through Themes",
- Key = Key.T.WithCtrl
- };
- menuItems.Add (menuItem);
- menuItems.Add (new Line ());
- _topSchemesSelector = new ()
- {
- // HighlightStates = MouseState.In,
- };
- _topSchemesSelector.ValueChanged += (_, args) =>
- {
- if (args.Value is null)
- {
- return;
- }
- CachedRunnableScheme = SchemeManager.GetSchemesForCurrentTheme ()!.Keys.ToArray () [(int)args.Value];
- SchemeName = CachedRunnableScheme;
- SetNeedsDraw ();
- };
- menuItem = new ()
- {
- Title = "Scheme for Runnable",
- SubMenu = new (
- [
- new ()
- {
- CommandView = _topSchemesSelector,
- HelpText = "Cycle Through schemes",
- Key = Key.S.WithCtrl
- }
- ])
- };
- menuItems.Add (menuItem);
- UpdateThemesMenu ();
- }
- else
- {
- menuItems.Add (new MenuItem ()
- {
- Title = "Configuration Manager is not Enabled",
- Enabled = false
- });
- }
- return menuItems.ToArray ();
- }
- View [] CreateDiagnosticMenuItems ()
- {
- List<View> menuItems = [];
- _diagnosticFlagsSelector = new ()
- {
- Styles = SelectorStyles.ShowNoneFlag,
- CanFocus = true
- };
- _diagnosticFlagsSelector.UsedHotKeys.Add (Key.D);
- _diagnosticFlagsSelector.AssignHotKeys = true;
- _diagnosticFlagsSelector.Value = Diagnostics;
- _diagnosticFlagsSelector.Activating += (sender, args) =>
- {
- _diagnosticFlags = (ViewDiagnosticFlags)((int)args.Context!.Source!.Data!);// (ViewDiagnosticFlags)_diagnosticFlagsSelector.Value;
- Diagnostics = _diagnosticFlags;
- };
- MenuItem diagFlagMenuItem = new MenuItem ()
- {
- CommandView = _diagnosticFlagsSelector,
- HelpText = "View Diagnostics"
- };
- diagFlagMenuItem.Accepting += (sender, args) =>
- {
- //_diagnosticFlags = (ViewDiagnosticFlags)_diagnosticFlagsSelector.Value;
- //Diagnostics = _diagnosticFlags;
- //args.Handled = true;
- };
- menuItems.Add (diagFlagMenuItem);
- menuItems.Add (new Line ());
- _disableMouseCb = new ()
- {
- Title = "_Disable Mouse",
- CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked,
- // Best practice for CheckBoxes in menus is to disable focus and highlight states
- CanFocus = false,
- HighlightStates = MouseState.None
- };
- //_disableMouseCb.CheckedStateChanged += (_, args) => { Application.IsMouseDisabled = args.Value == CheckState.Checked; };
- _disableMouseCb.Activating += (sender, args) =>
- {
- Application.IsMouseDisabled = !Application.IsMouseDisabled;
- _disableMouseCb.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.None;
- };
- menuItems.Add (
- new MenuItem
- {
- CommandView = _disableMouseCb,
- HelpText = "Disable Mouse"
- });
- return menuItems.ToArray ();
- }
- View [] CreateLoggingMenuItems ()
- {
- List<View?> menuItems = [];
- LogLevel [] logLevels = Enum.GetValues<LogLevel> ();
- _logLevelSelector = new ()
- {
- AssignHotKeys = true,
- Labels = Enum.GetNames<LogLevel> (),
- Value = logLevels.ToList ().IndexOf (Enum.Parse<LogLevel> (UICatalog.Options.DebugLogLevel)),
- // HighlightStates = MouseState.In,
- };
- _logLevelSelector.ValueChanged += (_, args) =>
- {
- UICatalog.Options = UICatalog.Options with { DebugLogLevel = Enum.GetName (logLevels [args.Value!.Value])! };
- UICatalog.LogLevelSwitch.MinimumLevel =
- UICatalog.LogLevelToLogEventLevel (Enum.Parse<LogLevel> (UICatalog.Options.DebugLogLevel));
- };
- menuItems.Add (
- new MenuItem
- {
- CommandView = _logLevelSelector,
- HelpText = "Cycle Through Log Levels",
- Key = Key.L.WithCtrl
- });
- // add a separator
- menuItems.Add (new Line ());
- menuItems.Add (
- new MenuItem (
- "_Open Log Folder",
- string.Empty,
- () => OpenUrl (UICatalog.LOGFILE_LOCATION)
- ));
- return menuItems.ToArray ()!;
- }
- }
- private void UpdateThemesMenu ()
- {
- if (_themesSelector is null)
- {
- return;
- }
- _themesSelector.Value = null;
- _themesSelector.AssignHotKeys = true;
- _themesSelector.UsedHotKeys.Clear ();
- _themesSelector.Labels = ThemeManager.GetThemeNames ().ToArray ();
- _themesSelector.Value = ThemeManager.GetThemeNames ().IndexOf (ThemeManager.GetCurrentThemeName ());
- if (_topSchemesSelector is null)
- {
- return;
- }
- _topSchemesSelector.AssignHotKeys = true;
- _topSchemesSelector.UsedHotKeys.Clear ();
- int? selectedScheme = _topSchemesSelector.Value;
- _topSchemesSelector.Labels = SchemeManager.GetSchemeNames ().ToArray ();
- _topSchemesSelector.Value = selectedScheme;
- if (CachedRunnableScheme is null || !SchemeManager.GetSchemeNames ().Contains (CachedRunnableScheme))
- {
- CachedRunnableScheme = SchemeManager.SchemesToSchemeName (Schemes.Base);
- }
- int newSelectedItem = SchemeManager.GetSchemeNames ().IndexOf (CachedRunnableScheme!);
- // if the item is in bounds then select it
- if (newSelectedItem >= 0 && newSelectedItem < SchemeManager.GetSchemeNames ().Count)
- {
- _topSchemesSelector.Value = newSelectedItem;
- }
- }
- #endregion MenuBar
- #region Scenario List
- private readonly TableView _scenarioList;
- private static int _cachedScenarioIndex;
- public static ObservableCollection<Scenario>? CachedScenarios { get; set; }
- // If set, holds the scenario the user selected to run
- public static Scenario? CachedSelectedScenario { get; set; }
- private TableView CreateScenarioList ()
- {
- // Create the scenario list. The contents of the scenario list changes whenever the
- // Category list selection changes (to show just the scenarios that belong to the selected
- // category).
- TableView scenarioList = new ()
- {
- X = Pos.Right (_categoryList!) - 1,
- Y = Pos.Bottom (_menuBar!),
- Width = Dim.Fill (),
- Height = Dim.Fill (Dim.Func (v => v!.Frame.Height, _statusBar)),
- //AllowsMarking = false,
- CanFocus = true,
- Title = "_Scenarios",
- BorderStyle = _categoryList!.BorderStyle,
- SuperViewRendersLineCanvas = true
- };
- // TableView provides many options for table headers. For simplicity, we turn all
- // of these off. By enabling FullRowSelect and turning off headers, TableView looks just
- // like a ListView
- scenarioList.FullRowSelect = true;
- scenarioList.Style.ShowHeaders = false;
- scenarioList.Style.ShowHorizontalHeaderOverline = false;
- scenarioList.Style.ShowHorizontalHeaderUnderline = false;
- scenarioList.Style.ShowHorizontalBottomline = false;
- scenarioList.Style.ShowVerticalCellLines = false;
- scenarioList.Style.ShowVerticalHeaderLines = false;
- /* By default, TableView lays out columns at render time and only
- * measures y rows of data at a time. Where y is the height of the
- * console. This is for the following reasons:
- *
- * - Performance, when tables have a large amount of data
- * - Defensive, prevents a single wide cell value pushing other
- * columns off-screen (requiring horizontal scrolling
- *
- * In the case of UICatalog here, such an approach is overkill so
- * we just measure all the data ourselves and set the appropriate
- * max widths as ColumnStyles
- */
- int longestName = CachedScenarios!.Max (s => s.GetName ().Length);
- scenarioList.Style.ColumnStyles.Add (
- 0,
- new () { MaxWidth = longestName, MinWidth = longestName, MinAcceptableWidth = longestName }
- );
- scenarioList.Style.ColumnStyles.Add (1, new () { MaxWidth = 1 });
- scenarioList.CellActivated += ScenarioView_OpenSelectedItem;
- // TableView typically is a grid where nav keys are biased for moving left/right.
- scenarioList.KeyBindings.Remove (Key.Home);
- scenarioList.KeyBindings.Add (Key.Home, Command.Start);
- scenarioList.KeyBindings.Remove (Key.End);
- scenarioList.KeyBindings.Add (Key.End, Command.End);
- // Ideally, TableView.MultiSelect = false would turn off any keybindings for
- // multi-select options. But it currently does not. UI Catalog uses Ctrl-A for
- // a shortcut to About.
- scenarioList.MultiSelect = false;
- scenarioList.KeyBindings.Remove (Key.A.WithCtrl);
- return scenarioList;
- }
- /// <summary>Launches the selected scenario, setting the global _selectedScenario</summary>
- /// <param name="e"></param>
- private void ScenarioView_OpenSelectedItem (object? sender, EventArgs? e)
- {
- if (CachedSelectedScenario is null)
- {
- // Save selected item state
- _cachedCategoryIndex = _categoryList!.SelectedItem;
- _cachedScenarioIndex = _scenarioList.SelectedRow;
- // Create new instance of scenario (even though Scenarios contains instances)
- var selectedScenarioName = (string)_scenarioList.Table [_scenarioList.SelectedRow, 0];
- CachedSelectedScenario = (Scenario)Activator.CreateInstance (
- CachedScenarios!.FirstOrDefault (
- s => s.GetName ()
- == selectedScenarioName
- )!
- .GetType ()
- )!;
- // Tell the main app to stop
- Application.RequestStop ();
- }
- }
- #endregion Scenario List
- #region Category List
- private readonly ListView? _categoryList;
- private static int? _cachedCategoryIndex;
- public static ObservableCollection<string>? CachedCategories { get; set; }
- private ListView CreateCategoryList ()
- {
- // Create the Category list view. This list never changes.
- ListView categoryList = new ()
- {
- X = 0,
- Y = Pos.Bottom (_menuBar!),
- Width = Dim.Auto (),
- Height = Dim.Fill (Dim.Func (v => v!.Frame.Height, _statusBar)),
- AllowsMarking = false,
- CanFocus = true,
- Title = "_Categories",
- BorderStyle = LineStyle.Rounded,
- SuperViewRendersLineCanvas = true,
- Source = new ListWrapper<string> (CachedCategories)
- };
- categoryList.OpenSelectedItem += (s, a) => { _scenarioList!.SetFocus (); };
- categoryList.SelectedItemChanged += CategoryView_SelectedChanged;
- // This enables the scrollbar by causing lazy instantiation to happen
- categoryList.VerticalScrollBar.AutoShow = true;
- return categoryList;
- }
- private void CategoryView_SelectedChanged (object? sender, ListViewItemEventArgs? e)
- {
- if (e is null or { Item: null })
- {
- return;
- }
- string item = CachedCategories! [e.Item.Value];
- ObservableCollection<Scenario> newScenarioList;
- if (e.Item == 0)
- {
- // First category is "All"
- newScenarioList = CachedScenarios!;
- }
- else
- {
- newScenarioList = new (CachedScenarios!.Where (s => s.GetCategories ().Contains (item)).ToList ());
- }
- _scenarioList.Table = new EnumerableTableSource<Scenario> (
- newScenarioList,
- new ()
- {
- { "Name", s => s.GetName () }, { "Description", s => s.GetDescription () }
- }
- );
- }
- #endregion Category List
- #region StatusBar
- private readonly StatusBar? _statusBar;
- [ConfigurationProperty (Scope = typeof (AppSettingsScope), OmitClassName = true)]
- [JsonPropertyName ("UICatalog.StatusBar")]
- public static bool ShowStatusBar { get; set; } = true;
- private Shortcut? _shQuit;
- private Shortcut? _shVersion;
- private CheckBox? _force16ColorsShortcutCb;
- private StatusBar CreateStatusBar ()
- {
- StatusBar statusBar = new ()
- {
- Visible = ShowStatusBar,
- AlignmentModes = AlignmentModes.IgnoreFirstOrLast,
- CanFocus = false
- };
- // ReSharper disable All
- statusBar.Height = Dim.Auto (
- DimAutoStyle.Auto,
- minimumContentDim: Dim.Func (_ => statusBar.Visible ? 1 : 0),
- maximumContentDim: Dim.Func (_ => statusBar.Visible ? 1 : 0));
- // ReSharper restore All
- _shQuit = new ()
- {
- CanFocus = false,
- Title = "Quit",
- Key = Application.QuitKey
- };
- _shVersion = new ()
- {
- Title = "Version Info",
- CanFocus = false
- };
- var statusBarShortcut = new Shortcut
- {
- Key = Key.F10,
- Title = "Show/Hide Status Bar",
- CanFocus = false
- };
- statusBarShortcut.Accepting += (sender, args) =>
- {
- statusBar.Visible = !_statusBar!.Visible;
- args.Handled = true;
- };
- _force16ColorsShortcutCb = new ()
- {
- Title = "16 color mode",
- CheckedState = Application.Driver!.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
- CanFocus = true
- };
- Shortcut force16ColorsShortcut = new ()
- {
- CanFocus = false,
- CommandView = _force16ColorsShortcutCb,
- HelpText = "",
- BindKeyToApplication = true,
- Key = Key.F7
- };
- force16ColorsShortcut.Accepting += (sender, args) =>
- {
- Application.Driver.Force16Colors = !Application.Driver.Force16Colors;
- _force16ColorsMenuItemCb!.CheckedState = Application.Driver.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
- SetNeedsDraw ();
- args.Handled = true;
- };
- statusBar.Add (
- _shQuit,
- statusBarShortcut,
- force16ColorsShortcut,
- _shVersion
- );
- if (UICatalog.Options.DontEnableConfigurationManagement)
- {
- statusBar.AddShortcutAt (statusBar.SubViews.ToList ().IndexOf (_shVersion), new Shortcut () { Title = "CM is Disabled" });
- }
- return statusBar;
- }
- #endregion StatusBar
- #region Configuration Manager
- /// <summary>
- /// Called when CM has applied changes.
- /// </summary>
- private void ConfigApplied ()
- {
- UpdateThemesMenu ();
- SchemeName = CachedRunnableScheme;
- if (_shQuit is { })
- {
- _shQuit.Key = Application.QuitKey;
- }
- if (_statusBar is { })
- {
- _statusBar.Visible = ShowStatusBar;
- }
- _disableMouseCb!.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked;
- _force16ColorsShortcutCb!.CheckedState = Application.Driver!.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
- Application.TopRunnableView?.SetNeedsDraw ();
- }
- private void ConfigAppliedHandler (object? sender, ConfigurationManagerEventArgs? a) { ConfigApplied (); }
- #endregion Configuration Manager
- /// <summary>
- /// Gets the message displayed in the About Box. `public` so it can be used from Unit tests.
- /// </summary>
- /// <returns></returns>
- public static string GetAboutBoxMessage ()
- {
- // NOTE: Do not use multiline verbatim strings here.
- // WSL gets all confused.
- StringBuilder msg = new ();
- msg.AppendLine ("UI Catalog: A comprehensive sample library and test app for");
- msg.AppendLine ();
- msg.AppendLine (
- """
- _______ _ _ _____ _
- |__ __| (_) | | / ____| (_)
- | | ___ _ __ _ __ ___ _ _ __ __ _| || | __ _ _ _
- | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | || | |_ | | | | |
- | | __/ | | | | | | | | | | | (_| | || |__| | |_| | |
- |_|\___|_| |_| |_| |_|_|_| |_|\__,_|_(_)_____|\__,_|_|
- """);
- msg.AppendLine ();
- msg.AppendLine ("v2 - Pre-Alpha");
- msg.AppendLine ();
- msg.AppendLine ("https://github.com/gui-cs/Terminal.Gui");
- return msg.ToString ();
- }
- public static void OpenUrl (string url)
- {
- if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows))
- {
- url = url.Replace ("&", "^&");
- Process.Start (new ProcessStartInfo ("cmd", $"/c start {url}") { CreateNoWindow = true });
- }
- else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux))
- {
- using var process = new Process
- {
- StartInfo = new ()
- {
- FileName = "xdg-open",
- Arguments = url,
- RedirectStandardError = true,
- RedirectStandardOutput = true,
- CreateNoWindow = true,
- UseShellExecute = false
- }
- };
- process.Start ();
- }
- else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX))
- {
- Process.Start ("open", url);
- }
- }
- }
|