From 55cb3e76b40e5c30cd1db5037dd999c4f2049499 Mon Sep 17 00:00:00 2001 From: dodexahedron Date: Wed, 21 Feb 2024 06:31:54 -0700 Subject: [PATCH] V2 Cleanup Batch 1 (Per #3253) (#3255) * Replace all 342 `== null` with `is null` * Replace 354 `!= null` with `is { }` * Wrap these in conditionals since they break tests against Release configuration The members they depend on do not exist in Release configuration * Split these up and dispose properly This test needs to be revisited for several reasons at some point. * Fix release configuration tests * Declare interface these already support * Annotate constructor properly and use throw helper * Move class to its own file * Rename these files so they nest in the solution explorer * Make this a record type and remove now-redundant/illegal members * Reference passing to avoid some struct copies * Simplify this * Carry reference passing through as appropriate * Turn this into a record struct * Remove unused internal constructor and its test It was only used by that test. * Simplify this constructor * This should be a property * Simplify constructor * Simplify GetHashCode * Mark this ignored just in case * Missed a couple of opportunities for reference passing * record struct already does this by value * Remove unused class * Simplify the type initializer and Reset method * Implement INotifyCollectionChanged and IDictionary by delegating to ColorSchemes * Fix for reflection-based configuration * Make CI build happy by disambiguiating this attribute * Add PERF, NOTE, QUESTION, and CONCURRENCY tags for the todo explorer * Make this string comparison faster. * Add a tag for unclear intent * This is a constant * Turn this into a constant via use of a unicode literal * Remove this method and its test It is unused There's no guarantee at all that the parent process is the terminal. There are good reasons, including that one, why there's no simple way to do it in .net. It's also of course a windows-only thing, if using WMI. * With the WMI method gone, we no longer need this * Make this more efficient * Add detail to this property's XmlDoc * Move the general properties up top because order matters * Make sure any constants defined at higher levels are not clobbered and define a couple more * Put InternalsVisibleTo in its own group * Sort dependencies alphabetically and update * Global usings * Split to one type per file * Collection expression * Fix naming * Inline to avoid copies * This is already a value copy (struct) * Combine to one non-destructive mutation * Avoid some potential boxing * Turn on null analysis here * Remove unnecessary cast and use real type name * Seal this * Fix name * Move nested class to a nested file (no type layout change made) * Undo naming change that isn't changed globally until next batch --- Terminal.Gui/Application.cs | 2 +- .../ConsoleDrivers/EscSeqUtils/EscSeqUtils.cs | 44 +----- .../Drawing/IntersectionDefinition.cs | 20 +++ Terminal.Gui/Drawing/IntersectionRuneType.cs | 19 +++ Terminal.Gui/Drawing/IntersectionType.cs | 28 ++++ Terminal.Gui/Drawing/LineCanvas.cs | 141 ++---------------- Terminal.Gui/Drawing/LineStyle.cs | 48 ++++++ Terminal.Gui/Drawing/Thickness.cs | 2 +- Terminal.Gui/Terminal.Gui.csproj | 29 ++-- .../Autocomplete/PopupAutocomplete.PopUp.cs | 29 ++++ .../Text/Autocomplete/PopupAutocomplete.cs | 30 +--- Terminal.Gui/View/ViewSubViews.cs | 12 +- Terminal.sln.DotSettings | 31 ++++ UnitTests/Input/EscSeqUtilsTests.cs | 13 -- 14 files changed, 225 insertions(+), 223 deletions(-) create mode 100644 Terminal.Gui/Drawing/IntersectionDefinition.cs create mode 100644 Terminal.Gui/Drawing/IntersectionRuneType.cs create mode 100644 Terminal.Gui/Drawing/IntersectionType.cs create mode 100644 Terminal.Gui/Drawing/LineStyle.cs create mode 100644 Terminal.Gui/Text/Autocomplete/PopupAutocomplete.PopUp.cs diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs index 46f2bc9ff..103bb8a9b 100644 --- a/Terminal.Gui/Application.cs +++ b/Terminal.Gui/Application.cs @@ -253,7 +253,7 @@ public static partial class Application else { List drivers = GetDriverTypes (); - Type driverType = drivers.FirstOrDefault (t => t.Name.ToLower () == ForceDriver.ToLower ()); + Type driverType = drivers.FirstOrDefault (t => t.Name.Equals (ForceDriver, StringComparison.InvariantCultureIgnoreCase)); if (driverType is { }) { diff --git a/Terminal.Gui/ConsoleDrivers/EscSeqUtils/EscSeqUtils.cs b/Terminal.Gui/ConsoleDrivers/EscSeqUtils/EscSeqUtils.cs index c308891cc..6b514abba 100644 --- a/Terminal.Gui/ConsoleDrivers/EscSeqUtils/EscSeqUtils.cs +++ b/Terminal.Gui/ConsoleDrivers/EscSeqUtils/EscSeqUtils.cs @@ -1,7 +1,3 @@ -using System.Diagnostics; -using System.Management; -using System.Runtime.InteropServices; - namespace Terminal.Gui; /// @@ -44,12 +40,12 @@ public static class EscSeqUtils /// /// Escape key code (ASCII 27/0x1B). /// - public static readonly char KeyEsc = (char)KeyCode.Esc; + public const char KeyEsc = (char)KeyCode.Esc; /// /// ESC [ - The CSI (Control Sequence Introducer). /// - public static readonly string CSI = $"{KeyEsc}["; + public const string CSI = "\u001B["; /// /// ESC [ ? 1047 h - Activate xterm alternative buffer (no backscroll) @@ -1019,42 +1015,6 @@ public static class EscSeqUtils //} } - // TODO: Move this out of here and into ConsoleDriver or somewhere else. - /// - /// Get the terminal that holds the console driver. - /// - /// The process. - /// If supported the executable console process, null otherwise. - public static Process GetParentProcess (Process process) - { - if (!RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) - { - return null; - } - - string query = "SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = " + process.Id; - - using (var mos = new ManagementObjectSearcher (query)) - { - foreach (ManagementObject mo in mos.Get ()) - { - if (mo ["ParentProcessId"] is { }) - { - try - { - var id = Convert.ToInt32 (mo ["ParentProcessId"]); - - return Process.GetProcessById (id); - } - catch - { } - } - } - } - - return null; - } - /// /// Ensures a console key is mapped to one that works correctly with ANSI escape sequences. /// diff --git a/Terminal.Gui/Drawing/IntersectionDefinition.cs b/Terminal.Gui/Drawing/IntersectionDefinition.cs new file mode 100644 index 000000000..d7f668aa1 --- /dev/null +++ b/Terminal.Gui/Drawing/IntersectionDefinition.cs @@ -0,0 +1,20 @@ +namespace Terminal.Gui; + +internal class IntersectionDefinition +{ + internal IntersectionDefinition (Point point, IntersectionType type, StraightLine line) + { + Point = point; + Type = type; + Line = line; + } + + /// The line that intersects + internal StraightLine Line { get; } + + /// The point at which the intersection happens + internal Point Point { get; } + + /// Defines how position relates to . + internal IntersectionType Type { get; } +} \ No newline at end of file diff --git a/Terminal.Gui/Drawing/IntersectionRuneType.cs b/Terminal.Gui/Drawing/IntersectionRuneType.cs new file mode 100644 index 000000000..467b8ff5b --- /dev/null +++ b/Terminal.Gui/Drawing/IntersectionRuneType.cs @@ -0,0 +1,19 @@ +namespace Terminal.Gui; + +/// The type of Rune that we will use before considering double width, curved borders etc +internal enum IntersectionRuneType +{ + None, + Dot, + ULCorner, + URCorner, + LLCorner, + LRCorner, + TopTee, + BottomTee, + RightTee, + LeftTee, + Cross, + HLine, + VLine +} \ No newline at end of file diff --git a/Terminal.Gui/Drawing/IntersectionType.cs b/Terminal.Gui/Drawing/IntersectionType.cs new file mode 100644 index 000000000..158e9ee8e --- /dev/null +++ b/Terminal.Gui/Drawing/IntersectionType.cs @@ -0,0 +1,28 @@ +namespace Terminal.Gui; + +internal enum IntersectionType +{ + /// There is no intersection + None, + + /// A line passes directly over this point traveling along the horizontal axis + PassOverHorizontal, + + /// A line passes directly over this point traveling along the vertical axis + PassOverVertical, + + /// A line starts at this point and is traveling up + StartUp, + + /// A line starts at this point and is traveling right + StartRight, + + /// A line starts at this point and is traveling down + StartDown, + + /// A line starts at this point and is traveling left + StartLeft, + + /// A line exists at this point who has 0 length + Dot +} \ No newline at end of file diff --git a/Terminal.Gui/Drawing/LineCanvas.cs b/Terminal.Gui/Drawing/LineCanvas.cs index 3a452a232..1a3fd3d46 100644 --- a/Terminal.Gui/Drawing/LineCanvas.cs +++ b/Terminal.Gui/Drawing/LineCanvas.cs @@ -1,58 +1,12 @@ -#nullable enable +#nullable enable namespace Terminal.Gui; -/// Defines the style of lines for a . -public enum LineStyle -{ - /// No border is drawn. - None, - - /// The border is drawn using thin line CM.Glyphs. - Single, - - /// The border is drawn using thin line glyphs with dashed (double and triple) straight lines. - Dashed, - - /// The border is drawn using thin line glyphs with short dashed (triple and quadruple) straight lines. - Dotted, - - /// The border is drawn using thin double line CM.Glyphs. - Double, - - /// The border is drawn using heavy line CM.Glyphs. - Heavy, - - /// The border is drawn using heavy line glyphs with dashed (double and triple) straight lines. - HeavyDashed, - - /// The border is drawn using heavy line glyphs with short dashed (triple and quadruple) straight lines. - HeavyDotted, - - /// The border is drawn using thin line glyphs with rounded corners. - Rounded, - - /// The border is drawn using thin line glyphs with rounded corners and dashed (double and triple) straight lines. - RoundedDashed, - - /// - /// The border is drawn using thin line glyphs with rounded corners and short dashed (triple and quadruple) - /// straight lines. - /// - RoundedDotted - - // TODO: Support Ruler - ///// - ///// The border is drawn as a diagnostic ruler ("|123456789..."). - ///// - //Ruler -} - /// Facilitates box drawing and line intersection detection and rendering. Does not support diagonal lines. public class LineCanvas : IDisposable { - private readonly List _lines = new (); + private readonly List _lines = []; - private readonly Dictionary runeResolvers = new () + private readonly Dictionary _runeResolvers = new () { { IntersectionRuneType.ULCorner, @@ -128,22 +82,19 @@ public class LineCanvas : IDisposable for (var i = 1; i < _lines.Count; i++) { - StraightLine line = _lines [i]; - Rect lineBounds = line.Bounds; - bounds = Rect.Union (bounds, lineBounds); + bounds = Rect.Union (bounds, _lines [i].Bounds); } - if (bounds.Width == 0) + if (bounds is {Width: 0} or {Height: 0}) { - bounds.Width = 1; + bounds = bounds with + { + Width = Math.Clamp (bounds.Width, 1, short.MaxValue), + Height = Math.Clamp (bounds.Height, 1, short.MaxValue) + }; } - if (bounds.Height == 0) - { - bounds.Height = 1; - } - - _cachedBounds = new Rect (bounds.X, bounds.Y, bounds.Width, bounds.Height); + _cachedBounds = bounds; } return _cachedBounds; @@ -358,7 +309,7 @@ public class LineCanvas : IDisposable private void ConfigurationManager_Applied (object? sender, ConfigurationManagerEventArgs e) { - foreach (KeyValuePair irr in runeResolvers) + foreach (KeyValuePair irr in _runeResolvers) { irr.Value.SetGlyphs (); } @@ -404,7 +355,7 @@ public class LineCanvas : IDisposable IntersectionRuneType runeType = GetRuneTypeForIntersects (intersects); - if (runeResolvers.TryGetValue (runeType, out IntersectionRuneResolver? resolver)) + if (_runeResolvers.TryGetValue (runeType, out IntersectionRuneResolver? resolver)) { return resolver.GetRuneForIntersects (driver, intersects); } @@ -892,68 +843,4 @@ public class LineCanvas : IDisposable _normal = Glyphs.URCorner; } } -} - -internal class IntersectionDefinition -{ - internal IntersectionDefinition (Point point, IntersectionType type, StraightLine line) - { - Point = point; - Type = type; - Line = line; - } - - /// The line that intersects - internal StraightLine Line { get; } - - /// The point at which the intersection happens - internal Point Point { get; } - - /// Defines how position relates to . - internal IntersectionType Type { get; } -} - -/// The type of Rune that we will use before considering double width, curved borders etc -internal enum IntersectionRuneType -{ - None, - Dot, - ULCorner, - URCorner, - LLCorner, - LRCorner, - TopTee, - BottomTee, - RightTee, - LeftTee, - Cross, - HLine, - VLine -} - -internal enum IntersectionType -{ - /// There is no intersection - None, - - /// A line passes directly over this point traveling along the horizontal axis - PassOverHorizontal, - - /// A line passes directly over this point traveling along the vertical axis - PassOverVertical, - - /// A line starts at this point and is traveling up - StartUp, - - /// A line starts at this point and is traveling right - StartRight, - - /// A line starts at this point and is traveling down - StartDown, - - /// A line starts at this point and is traveling left - StartLeft, - - /// A line exists at this point who has 0 length - Dot -} +} \ No newline at end of file diff --git a/Terminal.Gui/Drawing/LineStyle.cs b/Terminal.Gui/Drawing/LineStyle.cs new file mode 100644 index 000000000..6bb06212e --- /dev/null +++ b/Terminal.Gui/Drawing/LineStyle.cs @@ -0,0 +1,48 @@ +#nullable enable +namespace Terminal.Gui; + +/// Defines the style of lines for a . +public enum LineStyle +{ + /// No border is drawn. + None, + + /// The border is drawn using thin line CM.Glyphs. + Single, + + /// The border is drawn using thin line glyphs with dashed (double and triple) straight lines. + Dashed, + + /// The border is drawn using thin line glyphs with short dashed (triple and quadruple) straight lines. + Dotted, + + /// The border is drawn using thin double line CM.Glyphs. + Double, + + /// The border is drawn using heavy line CM.Glyphs. + Heavy, + + /// The border is drawn using heavy line glyphs with dashed (double and triple) straight lines. + HeavyDashed, + + /// The border is drawn using heavy line glyphs with short dashed (triple and quadruple) straight lines. + HeavyDotted, + + /// The border is drawn using thin line glyphs with rounded corners. + Rounded, + + /// The border is drawn using thin line glyphs with rounded corners and dashed (double and triple) straight lines. + RoundedDashed, + + /// + /// The border is drawn using thin line glyphs with rounded corners and short dashed (triple and quadruple) + /// straight lines. + /// + RoundedDotted + + // TODO: Support Ruler + ///// + ///// The border is drawn as a diagnostic ruler ("|123456789..."). + ///// + //Ruler +} diff --git a/Terminal.Gui/Drawing/Thickness.cs b/Terminal.Gui/Drawing/Thickness.cs index c5275b34b..2189ac9e2 100644 --- a/Terminal.Gui/Drawing/Thickness.cs +++ b/Terminal.Gui/Drawing/Thickness.cs @@ -273,7 +273,7 @@ public class Thickness : IEquatable int width = Math.Max (0, rect.Size.Width - Horizontal); int height = Math.Max (0, rect.Size.Height - Vertical); - return new Rect (new Point (x, y), new Size (width, height)); + return new (x, y, width, height); } /// diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index f4558ea42..dddf9f8fa 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -10,6 +10,14 @@ + + net8.0 + 12 + Terminal.Gui + Terminal.Gui + true + $(DefineConstants);JETBRAINS_ANNOTATIONS;CONTRACTS_FULL + portable @@ -18,13 +26,6 @@ TRACE;DEBUG_IDISPOSABLE portable - - net8.0 - 12 - Terminal.Gui - Terminal.Gui - true - @@ -40,12 +41,16 @@ - - - - + + + + + + + + @@ -83,6 +88,8 @@ + + diff --git a/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.PopUp.cs b/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.PopUp.cs new file mode 100644 index 000000000..80adef759 --- /dev/null +++ b/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.PopUp.cs @@ -0,0 +1,29 @@ +#nullable enable +namespace Terminal.Gui; + +public abstract partial class PopupAutocomplete +{ + private sealed class Popup : View + { + private readonly PopupAutocomplete _autoComplete; + + public Popup (PopupAutocomplete autoComplete) + { + this._autoComplete = autoComplete; + CanFocus = true; + WantMousePositionReports = true; + } + + public override bool MouseEvent (MouseEvent mouseEvent) { return _autoComplete.MouseEvent (mouseEvent); } + + public override void OnDrawContent (Rect contentArea) + { + if (!_autoComplete.LastPopupPos.HasValue) + { + return; + } + + _autoComplete.RenderOverlay (_autoComplete.LastPopupPos.Value); + } + } +} diff --git a/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs b/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs index b3a637b44..bf67d6321 100644 --- a/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs +++ b/Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs @@ -1,10 +1,10 @@ -namespace Terminal.Gui; +namespace Terminal.Gui; /// /// Renders an overlay on another view at a given point that allows selecting from a range of 'autocomplete' /// options. /// -public abstract class PopupAutocomplete : AutocompleteBase +public abstract partial class PopupAutocomplete : AutocompleteBase { private bool closed; private ColorScheme colorScheme; @@ -57,7 +57,9 @@ public abstract class PopupAutocomplete : AutocompleteBase /// public virtual int ScrollOffset { get; set; } + #nullable enable private Point? LastPopupPos { get; set; } + #nullable restore /// public override void EnsureSelectedIdxIsValid () @@ -552,28 +554,4 @@ public abstract class PopupAutocomplete : AutocompleteBase Visible = false; ManipulatePopup (); } - - private class Popup : View - { - private readonly PopupAutocomplete autocomplete; - - public Popup (PopupAutocomplete autocomplete) - { - this.autocomplete = autocomplete; - CanFocus = true; - WantMousePositionReports = true; - } - - public override bool MouseEvent (MouseEvent mouseEvent) { return autocomplete.MouseEvent (mouseEvent); } - - public override void OnDrawContent (Rect contentArea) - { - if (autocomplete.LastPopupPos is null) - { - return; - } - - autocomplete.RenderOverlay ((Point)autocomplete.LastPopupPos); - } - } } diff --git a/Terminal.Gui/View/ViewSubViews.cs b/Terminal.Gui/View/ViewSubViews.cs index 31cf5176f..56ca48f9e 100644 --- a/Terminal.Gui/View/ViewSubViews.cs +++ b/Terminal.Gui/View/ViewSubViews.cs @@ -1,4 +1,4 @@ -namespace Terminal.Gui; +namespace Terminal.Gui; public partial class View { @@ -358,7 +358,15 @@ public partial class View private bool _oldCanFocus; - /// + /// Gets or sets a value indicating whether this can focus. + /// + /// Override of .. + /// + /// Get accessor directly returns .. + /// + /// Set accessor validates before setting . + /// . + /// public override bool CanFocus { get => base.CanFocus; diff --git a/Terminal.sln.DotSettings b/Terminal.sln.DotSettings index a674682a7..930a19823 100644 --- a/Terminal.sln.DotSettings +++ b/Terminal.sln.DotSettings @@ -394,4 +394,35 @@ True True True + True + #FFCF9D32 + True + Performance + (?<=\W|^)(?<TAG>PERF)(\W|$)(.*) + Warning + True + True + #FFCF9D32 + True + Note + (?<=\W|^)(?<TAG>NOTE:)(\W|$)(.*) + Normal + True + #FFCF9D32 + True + Question + (?<=\W|^)(?<TAG>QUESTION:)(\W|$)(.*) + Question + True + #FFCF9D32 + True + Unclear Intent + (?<=\W|^)(?<TAG>UNCLEAR|INTENT)(\W|$)(.*) + Warning + True + #FFCF9D32 + True + Concurrency Issue + (?<=\W|^)(?<TAG>CONCURRENCY)(\W|$)(.*) + Warning diff --git a/UnitTests/Input/EscSeqUtilsTests.cs b/UnitTests/Input/EscSeqUtilsTests.cs index 3d5e460dd..c8838b750 100644 --- a/UnitTests/Input/EscSeqUtilsTests.cs +++ b/UnitTests/Input/EscSeqUtilsTests.cs @@ -1142,19 +1142,6 @@ public class EscSeqUtilsTests Assert.Equal (new Point (1, 2), pos); } - [Fact] - public void GetParentProcess_Tests () - { - if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) - { - Assert.NotNull (EscSeqUtils.GetParentProcess (Process.GetCurrentProcess ())); - } - else - { - Assert.Null (EscSeqUtils.GetParentProcess (Process.GetCurrentProcess ())); - } - } - [Fact] public void ResizeArray_ConsoleKeyInfo () {