From cdf85c791a737c5273e662b7f2db4da789798daa Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:17:37 -0500 Subject: [PATCH 1/8] Update IdeInfoDisplay.razor --- .../Shareds/Displays/Internals/IdeInfoDisplay.razor | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor b/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor index f078f98d5..42ef1de0e 100644 --- a/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor +++ b/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor @@ -180,6 +180,9 @@
  • Fix: primary constructor syntax.
  • +
  • + WIP_DESCRIPTION +
  • From 38199307fc688839ccf69f1b7405e2d4109ed7cf Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:16:15 -0500 Subject: [PATCH 2/8] Add button: Test rediscovery only happens once --- .../Displays/TestExplorerDisplay.razor | 14 ++++++++++ .../Displays/TestExplorerDisplay.razor.cs | 6 ++++ .../States/TestExplorerState.Effector.cs | 28 ++++++++++++++++++- .../Displays/StartupControlDisplay.razor | 2 +- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/Displays/TestExplorerDisplay.razor b/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/Displays/TestExplorerDisplay.razor index af7ca4872..1a2daf59a 100644 --- a/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/Displays/TestExplorerDisplay.razor +++ b/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/Displays/TestExplorerDisplay.razor @@ -49,6 +49,20 @@
    + + @{ + var iconDriver = new IconDriver( + AppOptionsStateWrap.Value.Options.IconSizeInPixels, + AppOptionsStateWrap.Value.Options.IconSizeInPixels); + } + + + Total: @(renderBatchValidated.TestExplorerState.TotalTestCount); NotRan: @(renderBatchValidated.TestExplorerState.NotRanTestHashSet.Count); Passed: @(renderBatchValidated.TestExplorerState.PassedTestHashSet.Count); diff --git a/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/Displays/TestExplorerDisplay.razor.cs b/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/Displays/TestExplorerDisplay.razor.cs index db44a3795..5f4b80762 100644 --- a/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/Displays/TestExplorerDisplay.razor.cs +++ b/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/Displays/TestExplorerDisplay.razor.cs @@ -53,6 +53,7 @@ protected override void OnInitialized() base.OnInitialized(); } + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) @@ -136,4 +137,9 @@ private void RegisterDetailsTextEditor(TextEditorModel model) return Task.CompletedTask; }); } + + private void DispatchShouldInitializeEffect() + { + Dispatcher.Dispatch(new TestExplorerState.ShouldInitializeEffect()); + } } \ No newline at end of file diff --git a/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/States/TestExplorerState.Effector.cs b/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/States/TestExplorerState.Effector.cs index 0f0069d90..2d01c761b 100644 --- a/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/States/TestExplorerState.Effector.cs +++ b/Source/Lib/Extensions/Extensions.DotNet/TestExplorers/States/TestExplorerState.Effector.cs @@ -26,6 +26,28 @@ public Effector( _dotNetSolutionStateWrap = dotNetSolutionStateWrap; } + /// + /// Each time the user opens the 'Test Explorer' panel, + /// a check is done to see if the data being displayed + /// is in sync with the user's selected .NET solution. + /// + /// If it is not in sync, then it starts discovering tests for each of the + /// projects in the solution. + /// + /// But, if the user cancels this task, if they change panel tabs + /// from the 'Test Explorer' to something else, when they return + /// it will once again try to discover tests in all the projects for the solution. + /// + /// This is very annoying from a user perspective. + /// So this field will track whether we've already started + /// the task to discover tests in all the projects for the solution or not. + /// + /// This is fine because there is a button in the top left of the panel that + /// has a 'refresh' icon and it will start this task if the + /// user manually clicks it, (even if they cancelled the automatic invocation). + /// + private string _intentToDiscoverTestsInSolutionFilePath = string.Empty; + [EffectMethod(typeof(DotNetSolutionState.StateHasChanged))] public Task HandleDotNetSolutionStateStateHasChanged(IDispatcher dispatcher) { @@ -46,8 +68,12 @@ public Task HandleUserInterfaceWasInitializedEffect(IDispatcher dispatcher) var testExplorerState = _testExplorerStateWrap.Value; - if (dotNetSolutionModel.AbsolutePath.Value != testExplorerState.SolutionFilePath) + if (dotNetSolutionModel.AbsolutePath.Value != testExplorerState.SolutionFilePath && + _intentToDiscoverTestsInSolutionFilePath != dotNetSolutionModel.AbsolutePath.Value) + { + _intentToDiscoverTestsInSolutionFilePath = dotNetSolutionModel.AbsolutePath.Value; dispatcher.Dispatch(new TestExplorerState.ShouldInitializeEffect()); + } return Task.CompletedTask; } diff --git a/Source/Lib/Ide/Ide.RazorLib/StartupControls/Displays/StartupControlDisplay.razor b/Source/Lib/Ide/Ide.RazorLib/StartupControls/Displays/StartupControlDisplay.razor index c7545aa41..df059ae93 100644 --- a/Source/Lib/Ide/Ide.RazorLib/StartupControls/Displays/StartupControlDisplay.razor +++ b/Source/Lib/Ide/Ide.RazorLib/StartupControls/Displays/StartupControlDisplay.razor @@ -1,6 +1,6 @@ @inherits Fluxor.Blazor.Web.Components.FluxorComponent -@{ +@{ var localStartupControlState = StartupControlStateWrap.Value; bool isExecuting; From 2098328e246ce18eb0b58d14f93ee33c65b7a589 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Wed, 18 Dec 2024 12:03:53 -0500 Subject: [PATCH 3/8] Parse array type definition --- .../BinderCase/CSharpBinder.Expressions.cs | 8 +-- .../Syntax/Nodes/TypeClauseNode.cs | 1 + .../Parsers/ExpressionAsStatementTests.cs | 49 ++++++++++++++++++- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index 39183535c..2bb7e0a47 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -1321,9 +1321,11 @@ public IExpressionNode TypeClauseMergeToken( } goto default; - case SyntaxKind.WithTokenContextualKeyword: - Console.WriteLine("case SyntaxKind.WithTokenContextualKeyword)"); - goto default; + case SyntaxKind.OpenSquareBracketToken: + typeClauseNode.ArrayRank++; + return typeClauseNode; + case SyntaxKind.CloseSquareBracketToken: + return typeClauseNode; default: if (UtilityApi.IsConvertibleToIdentifierToken(token.SyntaxKind)) { diff --git a/Source/Lib/TextEditor/CompilerServices/Syntax/Nodes/TypeClauseNode.cs b/Source/Lib/TextEditor/CompilerServices/Syntax/Nodes/TypeClauseNode.cs index 5e75e3ebd..2cd50e75d 100644 --- a/Source/Lib/TextEditor/CompilerServices/Syntax/Nodes/TypeClauseNode.cs +++ b/Source/Lib/TextEditor/CompilerServices/Syntax/Nodes/TypeClauseNode.cs @@ -71,6 +71,7 @@ public TypeClauseNode( TypeClauseNode IExpressionNode.ResultTypeClauseNode => TypeFacts.Pseudo.ToTypeClause(); public bool HasQuestionMark { get; set; } + public int ArrayRank { get; set; } /// /// TODO: Change this attribute node property. diff --git a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs index da95e9263..8a0894f59 100644 --- a/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs +++ b/Source/Tests/CompilerServices/CSharp/SmokeTests/Parsers/ExpressionAsStatementTests.cs @@ -1971,9 +1971,54 @@ public void VariableAssignmentExpressionNode() } [Fact] - public void Array() + public void Array_Definition_RankOne() { - var test = new Test(@"return someList[0];"); + var test = new Test(@"int[] someList;"); + var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; + WriteChildrenIndentedRecursive(topCodeBlock, nameof(topCodeBlock)); + var variableDeclarationNode = (VariableDeclarationNode)topCodeBlock.GetChildList().Single(); + Assert.Equal(SyntaxKind.VariableDeclarationNode, variableDeclarationNode.SyntaxKind); + Assert.Equal(1, variableDeclarationNode.TypeClauseNode.ArrayRank); + } + + [Fact] + public void Array_Definition_RankTwo() + { + var test = new Test(@"int[][] someList;"); + var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; + WriteChildrenIndentedRecursive(topCodeBlock, nameof(topCodeBlock)); + var variableDeclarationNode = (VariableDeclarationNode)topCodeBlock.GetChildList().Single(); + Assert.Equal(SyntaxKind.VariableDeclarationNode, variableDeclarationNode.SyntaxKind); + Assert.Equal(2, variableDeclarationNode.TypeClauseNode.ArrayRank); + } + + [Fact] + public void Array_Definition_Nullable() + { + var test = new Test(@"int[]? someList;"); + var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; + WriteChildrenIndentedRecursive(topCodeBlock, nameof(topCodeBlock)); + var variableDeclarationNode = (VariableDeclarationNode)topCodeBlock.GetChildList().Single(); + Assert.Equal(SyntaxKind.VariableDeclarationNode, variableDeclarationNode.SyntaxKind); + Assert.Equal(1, variableDeclarationNode.TypeClauseNode.ArrayRank); + Assert.True(variableDeclarationNode.TypeClauseNode.HasQuestionMark); + } + + [Fact] + public void Array_Assignment() + { + var test = new Test(@"someList = new int[1];"); + var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; + WriteChildrenIndentedRecursive(topCodeBlock, nameof(topCodeBlock)); + var returnStatementNode = (ReturnStatementNode)topCodeBlock.GetChildList().Single(); + Assert.Equal(SyntaxKind.ReturnStatementNode, returnStatementNode.SyntaxKind); + + } + + [Fact] + public void Array_Access() + { + var test = new Test(@"someList[0];"); var topCodeBlock = test.CompilationUnit.RootCodeBlockNode; WriteChildrenIndentedRecursive(topCodeBlock, nameof(topCodeBlock)); var returnStatementNode = (ReturnStatementNode)topCodeBlock.GetChildList().Single(); From 5cc431e018fe7cc25a42ef09ea736a3d91037756 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Wed, 18 Dec 2024 12:19:24 -0500 Subject: [PATCH 4/8] Show array in type clause node tooltip --- .../Internals/Symbols/TypeSyntaxDisplay.razor | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Source/Lib/TextEditor/TextEditors/Displays/Internals/Symbols/TypeSyntaxDisplay.razor b/Source/Lib/TextEditor/TextEditors/Displays/Internals/Symbols/TypeSyntaxDisplay.razor index 95226c552..c07229049 100644 --- a/Source/Lib/TextEditor/TextEditors/Displays/Internals/Symbols/TypeSyntaxDisplay.razor +++ b/Source/Lib/TextEditor/TextEditors/Displays/Internals/Symbols/TypeSyntaxDisplay.razor @@ -14,6 +14,7 @@ GenericArgumentsListingNode? genericArgumentsListingNode; GenericParametersListingNode? genericParametersListingNode; bool? hasQuestionMark; + int arrayRank; if (syntaxViewModelLocal.DefinitionNode is null && syntaxViewModelLocal.TargetNode is null && syntaxViewModelLocal.TargetSymbol is null) { @@ -24,6 +25,7 @@ genericArgumentsListingNode = null; genericParametersListingNode = null; hasQuestionMark = null; + arrayRank = 0; } else if (syntaxViewModelLocal.DefinitionNode is not null && syntaxViewModelLocal.DefinitionNode.SyntaxKind == SyntaxKind.TypeDefinitionNode) { @@ -41,6 +43,7 @@ genericArgumentsListingNode = typeDefinitionNode.GenericArgumentsListingNode; genericParametersListingNode = null; hasQuestionMark = null; + arrayRank = 0; } else if (syntaxViewModelLocal.TargetNode is not null && syntaxViewModelLocal.TargetNode.SyntaxKind == SyntaxKind.TypeClauseNode) { @@ -58,6 +61,7 @@ genericArgumentsListingNode = null; genericParametersListingNode = typeClauseNode.GenericParametersListingNode; hasQuestionMark = typeClauseNode.HasQuestionMark; + arrayRank = typeClauseNode.ArrayRank; } else if (syntaxViewModelLocal.TargetSymbol is not null && syntaxViewModelLocal.TargetSymbol.SyntaxKind == SyntaxKind.TypeSymbol) { @@ -68,6 +72,7 @@ genericArgumentsListingNode = null; genericParametersListingNode = null; hasQuestionMark = null; + arrayRank = 0; } else { @@ -78,6 +83,7 @@ genericArgumentsListingNode = null; genericParametersListingNode = null; hasQuestionMark = null; + arrayRank = 0; } } @@ -125,4 +131,12 @@ { ? } + + @if (arrayRank > 0) + { + for (int badIndex = 0; badIndex < arrayRank; badIndex++) + { + [] + } + } From 89b72033041135a1846df6c07161d2776fd931f1 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Wed, 18 Dec 2024 12:26:30 -0500 Subject: [PATCH 5/8] Skip over BangToken without causing a BadExpressionNode --- .../CSharp/BinderCase/CSharpBinder.Expressions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index 2bb7e0a47..fcb011589 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -847,6 +847,8 @@ public IExpressionNode EmptyMergeToken( var returnStatementNode = new ReturnStatementNode((KeywordToken)token, EmptyExpressionNode.Empty); parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, returnStatementNode)); return EmptyExpressionNode.Empty; + case SyntaxKind.BangToken: + return emptyExpressionNode; default: return new BadExpressionNode(CSharpFacts.Types.Void.ToTypeClause(), emptyExpressionNode, token); } From e85d82236d331b41a25ce2b006358b98651c1346 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Wed, 18 Dec 2024 12:44:22 -0500 Subject: [PATCH 6/8] Lex Pipe, PipePipe, Ampersand, AmpersandAmpersand --- .../CSharp/LexerCase/CSharpLexer.cs | 34 +++++++++++ .../CompilerServices/Syntax/SyntaxKind.cs | 4 ++ .../Syntax/Tokens/AmpersandAmpersandToken.cs | 17 ++++++ .../Syntax/Tokens/AmpersandToken.cs | 17 ++++++ .../Syntax/Tokens/PipePipeToken.cs | 17 ++++++ .../Syntax/Tokens/PipeToken.cs | 17 ++++++ .../CSharp/SmokeTests/Lexers/LexerTests.cs | 56 +++++++++++++++++++ 7 files changed, 162 insertions(+) create mode 100644 Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/AmpersandAmpersandToken.cs create mode 100644 Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/AmpersandToken.cs create mode 100644 Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/PipePipeToken.cs create mode 100644 Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/PipeToken.cs diff --git a/Source/Lib/CompilerServices/CSharp/LexerCase/CSharpLexer.cs b/Source/Lib/CompilerServices/CSharp/LexerCase/CSharpLexer.cs index ea3168f8c..d4d58d498 100644 --- a/Source/Lib/CompilerServices/CSharp/LexerCase/CSharpLexer.cs +++ b/Source/Lib/CompilerServices/CSharp/LexerCase/CSharpLexer.cs @@ -167,6 +167,40 @@ public static CSharpLexerOutput Lex(ResourceUri resourceUri, string sourceText) lexerOutput.SyntaxTokenList.Add(new QuestionMarkToken(textSpan)); } break; + case '|': + if (stringWalker.PeekCharacter(1) == '|') + { + var entryPositionIndex = stringWalker.PositionIndex; + stringWalker.ReadCharacter(); + stringWalker.ReadCharacter(); + var textSpan = new TextEditorTextSpan(entryPositionIndex, stringWalker.PositionIndex, (byte)GenericDecorationKind.None, stringWalker.ResourceUri, stringWalker.SourceText); + lexerOutput.SyntaxTokenList.Add(new PipePipeToken(textSpan)); + } + else + { + var entryPositionIndex = stringWalker.PositionIndex; + stringWalker.ReadCharacter(); + var textSpan = new TextEditorTextSpan(entryPositionIndex, stringWalker.PositionIndex, (byte)GenericDecorationKind.None, stringWalker.ResourceUri, stringWalker.SourceText); + lexerOutput.SyntaxTokenList.Add(new PipeToken(textSpan)); + } + break; + case '&': + if (stringWalker.PeekCharacter(1) == '&') + { + var entryPositionIndex = stringWalker.PositionIndex; + stringWalker.ReadCharacter(); + stringWalker.ReadCharacter(); + var textSpan = new TextEditorTextSpan(entryPositionIndex, stringWalker.PositionIndex, (byte)GenericDecorationKind.None, stringWalker.ResourceUri, stringWalker.SourceText); + lexerOutput.SyntaxTokenList.Add(new AmpersandAmpersandToken(textSpan)); + } + else + { + var entryPositionIndex = stringWalker.PositionIndex; + stringWalker.ReadCharacter(); + var textSpan = new TextEditorTextSpan(entryPositionIndex, stringWalker.PositionIndex, (byte)GenericDecorationKind.None, stringWalker.ResourceUri, stringWalker.SourceText); + lexerOutput.SyntaxTokenList.Add(new AmpersandToken(textSpan)); + } + break; case '*': { var entryPositionIndex = stringWalker.PositionIndex; diff --git a/Source/Lib/TextEditor/CompilerServices/Syntax/SyntaxKind.cs b/Source/Lib/TextEditor/CompilerServices/Syntax/SyntaxKind.cs index 2308fca7e..13bca3be3 100644 --- a/Source/Lib/TextEditor/CompilerServices/Syntax/SyntaxKind.cs +++ b/Source/Lib/TextEditor/CompilerServices/Syntax/SyntaxKind.cs @@ -28,6 +28,10 @@ public enum SyntaxKind EqualsEqualsToken, QuestionMarkToken, QuestionMarkQuestionMarkToken, + PipeToken, + PipePipeToken, + AmpersandToken, + AmpersandAmpersandToken, BangToken, StatementDelimiterToken, ArraySyntaxToken, diff --git a/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/AmpersandAmpersandToken.cs b/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/AmpersandAmpersandToken.cs new file mode 100644 index 000000000..6521c9dd5 --- /dev/null +++ b/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/AmpersandAmpersandToken.cs @@ -0,0 +1,17 @@ +using Luthetus.TextEditor.RazorLib.Lexers.Models; + +namespace Luthetus.TextEditor.RazorLib.CompilerServices.Syntax.Tokens; + +public struct AmpersandAmpersandToken : ISyntaxToken +{ + public AmpersandAmpersandToken(TextEditorTextSpan textSpan) + { + ConstructorWasInvoked = true; + TextSpan = textSpan; + } + + public TextEditorTextSpan TextSpan { get; } + public SyntaxKind SyntaxKind => SyntaxKind.AmpersandAmpersandToken; + public bool IsFabricated { get; init; } + public bool ConstructorWasInvoked { get; } +} diff --git a/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/AmpersandToken.cs b/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/AmpersandToken.cs new file mode 100644 index 000000000..786b9890a --- /dev/null +++ b/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/AmpersandToken.cs @@ -0,0 +1,17 @@ +using Luthetus.TextEditor.RazorLib.Lexers.Models; + +namespace Luthetus.TextEditor.RazorLib.CompilerServices.Syntax.Tokens; + +public struct AmpersandToken : ISyntaxToken +{ + public AmpersandToken(TextEditorTextSpan textSpan) + { + ConstructorWasInvoked = true; + TextSpan = textSpan; + } + + public TextEditorTextSpan TextSpan { get; } + public SyntaxKind SyntaxKind => SyntaxKind.AmpersandToken; + public bool IsFabricated { get; init; } + public bool ConstructorWasInvoked { get; } +} \ No newline at end of file diff --git a/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/PipePipeToken.cs b/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/PipePipeToken.cs new file mode 100644 index 000000000..0e3d38de6 --- /dev/null +++ b/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/PipePipeToken.cs @@ -0,0 +1,17 @@ +using Luthetus.TextEditor.RazorLib.Lexers.Models; + +namespace Luthetus.TextEditor.RazorLib.CompilerServices.Syntax.Tokens; + +public struct PipePipeToken : ISyntaxToken +{ + public PipePipeToken(TextEditorTextSpan textSpan) + { + ConstructorWasInvoked = true; + TextSpan = textSpan; + } + + public TextEditorTextSpan TextSpan { get; } + public SyntaxKind SyntaxKind => SyntaxKind.PipePipeToken; + public bool IsFabricated { get; init; } + public bool ConstructorWasInvoked { get; } +} \ No newline at end of file diff --git a/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/PipeToken.cs b/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/PipeToken.cs new file mode 100644 index 000000000..18703de49 --- /dev/null +++ b/Source/Lib/TextEditor/CompilerServices/Syntax/Tokens/PipeToken.cs @@ -0,0 +1,17 @@ +using Luthetus.TextEditor.RazorLib.Lexers.Models; + +namespace Luthetus.TextEditor.RazorLib.CompilerServices.Syntax.Tokens; + +public struct PipeToken : ISyntaxToken +{ + public PipeToken(TextEditorTextSpan textSpan) + { + ConstructorWasInvoked = true; + TextSpan = textSpan; + } + + public TextEditorTextSpan TextSpan { get; } + public SyntaxKind SyntaxKind => SyntaxKind.PipeToken; + public bool IsFabricated { get; init; } + public bool ConstructorWasInvoked { get; } +} \ No newline at end of file diff --git a/Source/Tests/CompilerServices/CSharp/SmokeTests/Lexers/LexerTests.cs b/Source/Tests/CompilerServices/CSharp/SmokeTests/Lexers/LexerTests.cs index 244d53bb7..729fa6922 100644 --- a/Source/Tests/CompilerServices/CSharp/SmokeTests/Lexers/LexerTests.cs +++ b/Source/Tests/CompilerServices/CSharp/SmokeTests/Lexers/LexerTests.cs @@ -136,6 +136,62 @@ public void LEX_BadToken() throw new NotImplementedException(); } + [Fact] + public void LEX_PipeToken() + { + var resourceUri = new ResourceUri("UnitTests"); + var sourceText = "|"; + var lexerOutput = CSharpLexer.Lex(resourceUri, sourceText); + + Assert.Equal(2, lexerOutput.SyntaxTokenList.Count); + var pipeToken = (PipeToken)lexerOutput.SyntaxTokenList[0]; + var endOfFileToken = (EndOfFileToken)lexerOutput.SyntaxTokenList[1]; + + Assert.Equal(SyntaxKind.PipeToken, pipeToken.SyntaxKind); + } + + [Fact] + public void LEX_PipePipeToken() + { + var resourceUri = new ResourceUri("UnitTests"); + var sourceText = "||"; + var lexerOutput = CSharpLexer.Lex(resourceUri, sourceText); + + Assert.Equal(2, lexerOutput.SyntaxTokenList.Count); + var pipePipeToken = (PipePipeToken)lexerOutput.SyntaxTokenList[0]; + var endOfFileToken = (EndOfFileToken)lexerOutput.SyntaxTokenList[1]; + + Assert.Equal(SyntaxKind.PipePipeToken, pipePipeToken.SyntaxKind); + } + + [Fact] + public void LEX_AmpersandToken() + { + var resourceUri = new ResourceUri("UnitTests"); + var sourceText = "&"; + var lexerOutput = CSharpLexer.Lex(resourceUri, sourceText); + + Assert.Equal(2, lexerOutput.SyntaxTokenList.Count); + var ampersandToken = (AmpersandToken)lexerOutput.SyntaxTokenList[0]; + var endOfFileToken = (EndOfFileToken)lexerOutput.SyntaxTokenList[1]; + + Assert.Equal(SyntaxKind.AmpersandToken, ampersandToken.SyntaxKind); + } + + [Fact] + public void LEX_AmpersandAmpersandToken() + { + var resourceUri = new ResourceUri("UnitTests"); + var sourceText = "&&"; + var lexerOutput = CSharpLexer.Lex(resourceUri, sourceText); + + Assert.Equal(2, lexerOutput.SyntaxTokenList.Count); + var ampersandAmpersandToken = (AmpersandAmpersandToken)lexerOutput.SyntaxTokenList[0]; + var endOfFileToken = (EndOfFileToken)lexerOutput.SyntaxTokenList[1]; + + Assert.Equal(SyntaxKind.AmpersandAmpersandToken, ampersandAmpersandToken.SyntaxKind); + } + [Fact] public void LEX_BangToken() { From 71fa5ead7d053ce24763e7ceecfe2df708021a95 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:36:54 -0500 Subject: [PATCH 7/8] --luth_te_preprocessor-directive-foreground-color --- .../CSharp/BinderCase/CSharpBinder.Expressions.cs | 6 ++++++ .../CSharp/LexerCase/CSharpLexer.cs | 13 +++++++++++-- .../Decoration/GenericDecorationMapper.cs | 2 +- .../Lib/TextEditor/wwwroot/luthetusTextEditor.css | 8 ++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs index fcb011589..1036d1990 100644 --- a/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs +++ b/Source/Lib/CompilerServices/CSharp/BinderCase/CSharpBinder.Expressions.cs @@ -848,6 +848,12 @@ public IExpressionNode EmptyMergeToken( parserModel.ExpressionList.Add((SyntaxKind.EndOfFileToken, returnStatementNode)); return EmptyExpressionNode.Empty; case SyntaxKind.BangToken: + case SyntaxKind.PipeToken: + case SyntaxKind.PipePipeToken: + case SyntaxKind.AmpersandToken: + case SyntaxKind.AmpersandAmpersandToken: + case SyntaxKind.PlusPlusToken: + case SyntaxKind.MinusMinusToken: return emptyExpressionNode; default: return new BadExpressionNode(CSharpFacts.Types.Void.ToTypeClause(), emptyExpressionNode, token); diff --git a/Source/Lib/CompilerServices/CSharp/LexerCase/CSharpLexer.cs b/Source/Lib/CompilerServices/CSharp/LexerCase/CSharpLexer.cs index d4d58d498..c383b3ae0 100644 --- a/Source/Lib/CompilerServices/CSharp/LexerCase/CSharpLexer.cs +++ b/Source/Lib/CompilerServices/CSharp/LexerCase/CSharpLexer.cs @@ -941,6 +941,7 @@ public static void LexPreprocessorDirectiveToken(ref CSharpLexerOutput lexerOutp // Declare outside the while loop to avoid overhead of redeclaring each loop? not sure var isNewLineCharacter = false; + var firstWhitespaceCharacterPositionIndex = -1; while (!stringWalker.IsEof) { @@ -950,6 +951,11 @@ public static void LexPreprocessorDirectiveToken(ref CSharpLexerOutput lexerOutp case '\n': isNewLineCharacter = true; break; + case '\t': + case ' ': + if (firstWhitespaceCharacterPositionIndex == -1) + firstWhitespaceCharacterPositionIndex = stringWalker.PositionIndex; + break; default: break; } @@ -959,11 +965,14 @@ public static void LexPreprocessorDirectiveToken(ref CSharpLexerOutput lexerOutp _ = stringWalker.ReadCharacter(); } + + if (firstWhitespaceCharacterPositionIndex == -1) + firstWhitespaceCharacterPositionIndex = stringWalker.PositionIndex; var textSpan = new TextEditorTextSpan( entryPositionIndex, - stringWalker.PositionIndex, - (byte)GenericDecorationKind.None, + firstWhitespaceCharacterPositionIndex, + (byte)GenericDecorationKind.PreprocessorDirective, stringWalker.ResourceUri, stringWalker.SourceText); diff --git a/Source/Lib/TextEditor/CompilerServices/GenericLexer/Decoration/GenericDecorationMapper.cs b/Source/Lib/TextEditor/CompilerServices/GenericLexer/Decoration/GenericDecorationMapper.cs index 87a10ad82..d4a4bd255 100644 --- a/Source/Lib/TextEditor/CompilerServices/GenericLexer/Decoration/GenericDecorationMapper.cs +++ b/Source/Lib/TextEditor/CompilerServices/GenericLexer/Decoration/GenericDecorationMapper.cs @@ -20,7 +20,7 @@ public string Map(byte decorationByte) GenericDecorationKind.CommentSingleLine => "luth_te_comment", GenericDecorationKind.CommentMultiLine => "luth_te_comment", GenericDecorationKind.Function => "luth_te_method", - GenericDecorationKind.PreprocessorDirective => "luth_te_keyword", + GenericDecorationKind.PreprocessorDirective => "luth_te_preprocessor-directive", GenericDecorationKind.DeliminationExtended => "luth_te_string-literal", GenericDecorationKind.Type => "luth_te_type", _ => string.Empty, diff --git a/Source/Lib/TextEditor/wwwroot/luthetusTextEditor.css b/Source/Lib/TextEditor/wwwroot/luthetusTextEditor.css index 5ea3e8b41..7b11e0aea 100644 --- a/Source/Lib/TextEditor/wwwroot/luthetusTextEditor.css +++ b/Source/Lib/TextEditor/wwwroot/luthetusTextEditor.css @@ -63,6 +63,10 @@ color: var(--luth_te_keyword-control-foreground-color); } +.luth_te_preprocessor-directive { + color: var(--luth_te_preprocessor-directive-foreground-color); +} + .luth_te_comment { color: var(--luth_te_comment-foreground-color); } @@ -542,6 +546,7 @@ --luth_te_string-literal-escape-character-secondary-foreground-color: var(--luth_te_associated-key-color); --luth_te_keyword-foreground-color: rgb(0, 0, 255); --luth_te_keyword-control-foreground-color: rgb(143, 8, 196); + --luth_te_preprocessor-directive-foreground-color: rgb(143, 8, 196); --luth_te_comment-foreground-color: rgb(0, 128, 0); --luth_te_tag-name-foreground-color: rgb(128, 0, 0); --luth_te_injected-language-fragment-color: rgb(225, 80, 220); @@ -628,6 +633,7 @@ --luth_te_string-literal-escape-character-secondary-foreground-color: var(--luth_te_associated-key-color); --luth_te_keyword-foreground-color: rgb(86, 156, 214); --luth_te_keyword-control-foreground-color: rgb(197, 134, 192); + --luth_te_preprocessor-directive-foreground-color: rgb(197, 134, 192); --luth_te_comment-foreground-color: rgb(106, 153, 85); --luth_te_tag-name-foreground-color: rgb(86, 156, 214); --luth_te_injected-language-fragment-color: rgb(197, 134, 192); @@ -714,6 +720,7 @@ --luth_te_string-literal-escape-character-secondary-foreground-color: rgb(230, 110, 160); --luth_te_keyword-foreground-color: rgb(215, 150, 70); --luth_te_keyword-control-foreground-color: rgb(215, 100, 100); + --luth_te_preprocessor-directive-foreground-color: rgb(215, 100, 100); --luth_te_comment-foreground-color: rgb(142, 142, 142); --luth_te_tag-name-foreground-color: var(--luth_te_keyword-foreground-color); --luth_te_injected-language-fragment-color: rgb(215, 107, 179); @@ -800,6 +807,7 @@ --luth_te_string-literal-escape-character-secondary-foreground-color: var(--luth_te_associated-key-color); --luth_te_keyword-foreground-color: rgb(170,0,250); --luth_te_keyword-control-foreground-color: rgb(215,0,0); + --luth_te_preprocessor-directive-foreground-color: rgb(215,0,0); --luth_te_comment-foreground-color: rgb(120, 120, 120); --luth_te_tag-name-foreground-color: var(--luth_te_keyword-foreground-color); --luth_te_injected-language-fragment-color: rgb(200, 0, 200); From 8aa5744625c258df58bff7b2df043f5a69417048 Mon Sep 17 00:00:00 2001 From: Luthetus <45454132+huntercfreeman@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:07:03 -0500 Subject: [PATCH 8/8] v0.9.7.10 --- .../Ide.RazorLib/Luthetus.Ide.RazorLib.csproj | 2 +- .../Displays/Internals/IdeInfoDisplay.razor | 28 ++++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj b/Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj index 181784a2b..84fbf8cf7 100644 --- a/Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj +++ b/Source/Lib/Ide/Ide.RazorLib/Luthetus.Ide.RazorLib.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - 0.9.7.9 + 0.9.7.10 diff --git a/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor b/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor index 42ef1de0e..fcc354850 100644 --- a/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor +++ b/Source/Lib/Ide/Ide.RazorLib/Shareds/Displays/Internals/IdeInfoDisplay.razor @@ -172,16 +172,36 @@ Recent Changes:
    -
    v 0.9.7.9 (WIP_DATE)
    +
    v 0.9.7.10 (2024-12-18)
    • - Fix: 'this' keyword in function arguments listing. + Lex preprocessor directive
    • - Fix: primary constructor syntax. + Lex Pipe, PipePipe, Ampersand, AmpersandAmpersand +
    • +
    • + Skip over BangToken without causing a BadExpressionNode +
    • +
    • + Show array in type clause node tooltip +
    • +
    • + Parse array type definition +
    • +
    • + Add button: Test rediscovery only happens once
    • +
    +
    +
    +
    v 0.9.7.9 (2024-12-17)
    +
    • - WIP_DESCRIPTION + Fix: 'this' keyword in function arguments listing. +
    • +
    • + Fix: primary constructor syntax.