Merge pull request #4 from mahalex/mapplication

Text viewer
This commit is contained in:
Alexander Luzgarev 2020-07-14 12:10:37 +02:00 committed by GitHub
commit f4921ac9f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1144 additions and 1 deletions

View File

@ -0,0 +1,14 @@
using Parser;
namespace MApplication
{
internal static class CodeProcessor
{
public static DisplayText GetText(SyntaxTree tree)
{
var visitor = new ColoringVisitor(StyleSchemeFactory.GetDefaultScheme());
visitor.Visit(tree.Root);
return new DisplayText(visitor.GetLines());
}
}
}

View File

@ -0,0 +1,461 @@
using Parser;
using Parser.Internal;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
namespace MApplication
{
internal class ColoringVisitor : SyntaxWalker
{
private readonly ImmutableList<DisplayLine>.Builder Builder;
private ImmutableList<DisplayLineChunk>.Builder CurrentLineBuilder;
private readonly StyleScheme _scheme;
private int _currentLine;
public ColoringVisitor(StyleScheme scheme)
{
Builder = ImmutableList.CreateBuilder<DisplayLine>();
CurrentLineBuilder = ImmutableList.CreateBuilder<DisplayLineChunk>();
_currentLine = 0;
_scheme = scheme;
}
public override void VisitToken(SyntaxToken token)
{
ProcessTriviaList(token.LeadingTrivia);
CurrentLineBuilder.Add(new DisplayLineChunk(token.Text.AsMemory(), _scheme.DefaultToken));
ProcessTriviaList (token.TrailingTrivia);
}
private void ProcessTriviaList(IReadOnlyList<SyntaxTrivia> triviaList)
{
foreach (var trivia in triviaList)
{
ProcessTrivia(trivia);
}
}
private void FinishLine()
{
Builder.Add(new DisplayLine(CurrentLineBuilder.ToImmutable()));
CurrentLineBuilder.Clear();
_currentLine++;
}
private void ProcessTrivia(SyntaxTrivia trivia)
{
if (trivia.Text.Contains('\n'))
{
var first = true;
foreach (var part in trivia.Text.Split('\n'))
{
if (first)
{
first = false;
} else
{
FinishLine();
}
CurrentLineBuilder.Add(new DisplayLineChunk(part.AsMemory(), _scheme.Trivia));
}
}
else
{
CurrentLineBuilder.Add(new DisplayLineChunk(trivia.Text.AsMemory(), _scheme.Trivia));
}
}
public void AddToken(SyntaxToken token, Style style)
{
ProcessTriviaList(token.LeadingTrivia);
CurrentLineBuilder.Add(new DisplayLineChunk(token.Text.AsMemory(), style));
ProcessTriviaList(token.TrailingTrivia);
}
public override void VisitFile(FileSyntaxNode node)
{
Visit(node.StatementList);
AddToken(node.EndOfFile, _scheme.Keyword);
}
public override void VisitBaseClassList(BaseClassListSyntaxNode node)
{
AddToken(node.LessSign, _scheme.Punctuation);
Visit(node.BaseClasses);
}
public override void VisitClassDeclaration(ClassDeclarationSyntaxNode node)
{
AddToken(node.ClassdefKeyword, _scheme.Keyword);
Visit(node.Attributes);
Visit(node.ClassName);
Visit(node.BaseClassList);
Visit(node.Nodes);
AddToken(node.EndKeyword, _scheme.Keyword);
}
public override void VisitList(SyntaxNodeOrTokenList list)
{
foreach (var nodeOrToken in list)
{
if (nodeOrToken.IsToken)
{
var token = nodeOrToken.AsToken();
if (token.Kind == TokenKind.IdentifierToken)
{
AddToken(token, _scheme.Identifier);
}
else if (SyntaxFacts.IsBracket(token.Kind))
{
AddToken(token, _scheme.Bracket);
}
else
{
AddToken(token, _scheme.Punctuation);
}
}
else
{
Visit(nodeOrToken.AsNode());
}
}
}
public override void VisitMethodsList(MethodsListSyntaxNode node)
{
AddToken(node.MethodsKeyword, _scheme.Keyword);
Visit(node.Attributes);
Visit(node.Methods);
AddToken(node.EndKeyword, _scheme.Keyword);
}
public override void VisitPropertiesList(PropertiesListSyntaxNode node)
{
AddToken(node.PropertiesKeyword, _scheme.Keyword);
Visit(node.Attributes);
Visit(node.Properties);
AddToken(node.EndKeyword, _scheme.Keyword);
}
public override void VisitMethodDefinition(MethodDefinitionSyntaxNode node)
{
AddToken(node.FunctionKeyword, _scheme.Keyword);
Visit(node.OutputDescription);
Visit(node.InputDescription);
Visit(node.Commas);
Visit(node.Body);
Visit(node.EndKeyword);
}
public override void VisitEndKeyword(EndKeywordSyntaxNode node)
{
AddToken(node.EndKeyword, _scheme.Keyword);
}
public override void VisitFunctionDeclaration(FunctionDeclarationSyntaxNode node)
{
AddToken(node.FunctionKeyword, _scheme.Keyword);
Visit(node.OutputDescription);
AddToken(node.Name, _scheme.Identifier);
Visit(node.InputDescription);
Visit(node.Commas);
Visit(node.Body);
Visit(node.EndKeyword);
}
public override void VisitIfStatement(IfStatementSyntaxNode node)
{
AddToken(node.IfKeyword, _scheme.ControlKeyword);
Visit(node.Condition);
Visit(node.OptionalCommas);
Visit(node.Body);
Visit(node.ElseifClauses);
Visit(node.ElseClause);
AddToken(node.EndKeyword, _scheme.ControlKeyword);
}
public override void VisitElseClause(ElseClause node)
{
AddToken(node.ElseKeyword, _scheme.ControlKeyword);
Visit(node.Body);
}
public override void VisitElseifClause(ElseifClause node)
{
AddToken(node.ElseifKeyword, _scheme.ControlKeyword);
Visit(node.Condition);
Visit(node.Body);
}
public override void VisitAbstractMethodDeclaration(AbstractMethodDeclarationSyntaxNode node)
{
Visit(node.OutputDescription);
Visit(node.Name);
Visit(node.InputDescription);
}
public override void VisitAssignmentExpression(AssignmentExpressionSyntaxNode node)
{
Visit(node.Lhs);
AddToken(node.AssignmentSign, _scheme.Operator);
Visit(node.Rhs);
}
public override void VisitExpressionStatement(ExpressionStatementSyntaxNode node)
{
Visit(node.Expression);
}
public override void VisitArrayLiteralExpression(ArrayLiteralExpressionSyntaxNode node)
{
AddToken(node.OpeningSquareBracket, _scheme.Bracket);
Visit(node.Nodes);
AddToken(node.ClosingSquareBracket, _scheme.Bracket);
}
public override void VisitCellArrayLiteralExpression(CellArrayLiteralExpressionSyntaxNode node)
{
AddToken(node.OpeningBrace, _scheme.Bracket);
Visit(node.Nodes);
AddToken(node.ClosingBrace, _scheme.Bracket);
}
public override void VisitIdentifierName(IdentifierNameSyntaxNode node)
{
AddToken(node.Name, _scheme.Identifier);
}
public override void VisitForStatement(ForStatementSyntaxNode node)
{
AddToken(node.ForKeyword, _scheme.ControlKeyword);
Visit(node.Assignment);
Visit(node.OptionalCommas);
Visit(node.Body);
AddToken(node.EndKeyword, _scheme.ControlKeyword);
}
public override void VisitSwitchStatement(SwitchStatementSyntaxNode node)
{
AddToken(node.SwitchKeyword, _scheme.ControlKeyword);
Visit(node.SwitchExpression);
Visit(node.OptionalCommas);
Visit(node.Cases);
AddToken(node.EndKeyword, _scheme.ControlKeyword);
}
public override void VisitWhileStatement(WhileStatementSyntaxNode node)
{
AddToken(node.WhileKeyword, _scheme.ControlKeyword);
Visit(node.Condition);
Visit(node.OptionalCommas);
Visit(node.Body);
AddToken(node.EndKeyword, _scheme.ControlKeyword);
}
public override void VisitUnquotedStringLiteral(UnquotedStringLiteralSyntaxNode node)
{
AddToken(node.StringToken, _scheme.UnquotedStringLiteral);
}
public override void VisitStringLiteral(StringLiteralSyntaxNode node)
{
AddToken(node.StringToken, _scheme.StringLiteral);
}
public override void VisitBinaryOperationExpression(BinaryOperationExpressionSyntaxNode node)
{
Visit(node.Lhs);
AddToken(node.Operation, _scheme.Operator);
Visit(node.Rhs);
}
public override void VisitFunctionCallExpression(FunctionCallExpressionSyntaxNode node)
{
Visit(node.FunctionName);
AddToken(node.OpeningBracket, _scheme.Bracket);
Visit(node.Nodes);
AddToken(node.ClosingBracket, _scheme.Bracket);
}
public override void VisitSwitchCase(SwitchCaseSyntaxNode node)
{
AddToken(node.CaseKeyword, _scheme.ControlKeyword);
Visit(node.CaseIdentifier);
Visit(node.OptionalCommas);
Visit(node.Body);
}
public override void VisitCatchClause(CatchClauseSyntaxNode node)
{
AddToken(node.CatchKeyword, _scheme.ControlKeyword);
Visit(node.CatchBody);
}
public override void VisitTryCatchStatement(TryCatchStatementSyntaxNode node)
{
AddToken(node.TryKeyword, _scheme.ControlKeyword);
Visit(node.TryBody);
Visit(node.CatchClause);
AddToken(node.EndKeyword, _scheme.ControlKeyword);
}
public override void VisitCommandExpression(CommandExpressionSyntaxNode node)
{
Visit(node.CommandName);
Visit(node.Arguments);
}
public override void VisitNumberLiteral(NumberLiteralSyntaxNode node)
{
AddToken(node.Number, _scheme.NumberLiteral);
}
public override void VisitUnaryPrefixOperationExpression(UnaryPrefixOperationExpressionSyntaxNode node)
{
AddToken(node.Operation, _scheme.Operator);
Visit(node.Operand);
}
public override void VisitUnaryPostixOperationExpression(UnaryPostixOperationExpressionSyntaxNode node)
{
Visit(node.Operand);
AddToken(node.Operation, _scheme.Operator);
}
public override void VisitBaseClassInvokation(BaseClassInvokationSyntaxNode node)
{
Visit(node.MethodName);
AddToken(node.AtSign, _scheme.Operator);
Visit(node.BaseClassNameAndArguments);
}
public override void VisitAttributeAssignment(AttributeAssignmentSyntaxNode node)
{
AddToken(node.AssignmentSign, _scheme.Operator);
Visit(node.Value);
}
public override void VisitAttribute(AttributeSyntaxNode node)
{
Visit(node.Name);
Visit(node.Assignment);
}
public override void VisitAttributeList(AttributeListSyntaxNode node)
{
AddToken(node.OpeningBracket, _scheme.Bracket);
Visit(node.Nodes);
AddToken(node.ClosingBracket, _scheme.Bracket);
}
public override void VisitCellArrayElementAccessExpression(CellArrayElementAccessExpressionSyntaxNode node)
{
Visit(node.Expression);
AddToken(node.OpeningBrace, _scheme.Bracket);
Visit(node.Nodes);
AddToken(node.ClosingBrace, _scheme.Bracket);
}
public override void VisitCompoundName(CompoundNameSyntaxNode node)
{
Visit(node.Nodes);
}
public override void VisitDoubleQuotedStringLiteral(DoubleQuotedStringLiteralSyntaxNode node)
{
AddToken(node.StringToken, _scheme.StringLiteral);
}
public override void VisitEmptyExpression(EmptyExpressionSyntaxNode node)
{
}
public override void VisitEmptyStatement(EmptyStatementSyntaxNode node)
{
AddToken(node.Semicolon, _scheme.Punctuation);
}
public override void VisitEnumerationList(EnumerationListSyntaxNode node)
{
AddToken(node.EnumerationKeyword, _scheme.Keyword);
Visit(node.Attributes);
Visit(node.Items);
AddToken(node.EndKeyword, _scheme.Keyword);
}
public override void VisitEventsList(EventsListSyntaxNode node)
{
AddToken(node.EventsKeyword, _scheme.Keyword);
Visit(node.Attributes);
Visit(node.Events);
AddToken(node.EndKeyword, _scheme.Keyword);
}
public override void VisitEnumerationItemValue(EnumerationItemValueSyntaxNode node)
{
AddToken(node.OpeningBracket, _scheme.Punctuation);
Visit(node.Values);
AddToken(node.ClosingBracket, _scheme.Punctuation);
}
public override void VisitEnumerationItem(EnumerationItemSyntaxNode node)
{
Visit(node.Name);
Visit(node.Values);
Visit(node.Commas);
}
public override void VisitFunctionInputDescription(FunctionInputDescriptionSyntaxNode node)
{
AddToken(node.OpeningBracket, _scheme.Bracket);
Visit(node.ParameterList);
AddToken(node.ClosingBracket, _scheme.Bracket);
}
public override void VisitFunctionOutputDescription(FunctionOutputDescriptionSyntaxNode node)
{
Visit(node.OutputList);
AddToken(node.AssignmentSign, _scheme.Operator);
}
public override void VisitIndirectMemberAccess(IndirectMemberAccessSyntaxNode node)
{
AddToken(node.OpeningBracket, _scheme.Bracket);
Visit(node.Expression);
AddToken(node.ClosingBracket, _scheme.Bracket);
}
public override void VisitLambda(LambdaSyntaxNode node)
{
AddToken(node.AtSign, _scheme.Operator);
Visit(node.Input);
Visit(node.Body);
}
public override void VisitNamedFunctionHandle(NamedFunctionHandleSyntaxNode node)
{
AddToken(node.AtSign, _scheme.Operator);
Visit(node.FunctionName);
}
public override void VisitMemberAccess(MemberAccessSyntaxNode node)
{
Visit(node.LeftOperand);
AddToken(node.Dot, _scheme.Operator);
Visit(node.RightOperand);
}
public override void VisitParenthesizedExpression(ParenthesizedExpressionSyntaxNode node)
{
AddToken(node.OpeningBracket, _scheme.Operator);
Visit(node.Expression);
AddToken(node.ClosingBracket, _scheme.Operator);
}
public ImmutableList<DisplayLine> GetLines()
{
return Builder.ToImmutable();
}
}
}

View File

@ -0,0 +1,57 @@
using System;
namespace MApplication
{
internal class ConsoleWindowView : IOutputView
{
public ConsoleWindowView(int startingColumn, int startingLine, int width, int height)
{
StartingColumn = startingColumn;
StartingLine = startingLine;
Width = width;
Height = height;
}
public int StartingColumn { get; }
public int StartingLine { get; }
public int Width { get; }
public int Height { get; }
public void HideCursor()
{
Console.CursorVisible = false;
}
public void MoveCursorTo(int column, int line)
{
Console.CursorLeft = StartingColumn + column;
Console.CursorTop = StartingLine + line;
}
public void SetStyle(Style style)
{
if (Console.ForegroundColor != style.ForegroundColor)
{
Console.ForegroundColor = style.ForegroundColor;
}
if (Console.BackgroundColor != style.BackgroundColor)
{
Console.BackgroundColor = style.BackgroundColor;
}
}
public void ShowCursor()
{
Console.CursorVisible = true;
}
public void WriteText(string s)
{
Console.Write(s);
}
}
}

View File

@ -0,0 +1,18 @@
using System.Collections.Immutable;
using System.Linq;
namespace MApplication
{
internal class DisplayLine
{
public DisplayLine(ImmutableList<DisplayLineChunk> chunks)
{
Chunks = chunks;
Width = chunks.Sum(c => c.Width);
}
public ImmutableList<DisplayLineChunk> Chunks { get; }
public int Width { get; }
}
}

View File

@ -0,0 +1,19 @@
using System;
namespace MApplication
{
internal class DisplayLineChunk
{
public DisplayLineChunk(ReadOnlyMemory<char> text, Style style)
{
Text = text;
Style = style;
}
public ReadOnlyMemory<char> Text { get; }
public Style Style { get; }
public int Width => Text.Length;
}
}

View File

@ -0,0 +1,14 @@
using System.Collections.Immutable;
namespace MApplication
{
internal class DisplayText
{
public DisplayText(ImmutableList<DisplayLine> lines)
{
Lines = lines;
}
public ImmutableList<DisplayLine> Lines { get; }
}
}

View File

@ -0,0 +1,286 @@
using System;
namespace MApplication
{
internal class DisplayTextViewPort
{
public DisplayTextViewPort(
DisplayText text,
int width,
int height,
int startingColumn = 0,
int startingLine = 0,
int cursorAbsoluteColumn = 0,
int cursorAbsoluteLine = 0,
int virtualCursorAbsoluteColumn = 0)
{
Text = text;
Width = width;
Height = height;
StartingColumn = startingColumn;
StartingLine = startingLine;
CursorAbsoluteColumn = cursorAbsoluteColumn;
CursorAbsoluteLine = cursorAbsoluteLine;
VirtualCursorAbsoluteColumn = virtualCursorAbsoluteColumn;
}
public DisplayText Text { get; }
public int Width { get; }
public int Height { get; }
public int StartingColumn { get; }
public int StartingLine { get; }
public int CursorRelativeColumn => CursorAbsoluteColumn - StartingColumn;
public int CursorRelativeLine => CursorAbsoluteLine - StartingLine;
public int CursorAbsoluteColumn { get; }
public int CursorAbsoluteLine { get; }
public int VirtualCursorAbsoluteColumn { get; }
public int CurrentLineWidth => Text.Lines[CursorAbsoluteLine].Width;
public DisplayTextViewPort CursorLeft(out bool needsRedraw)
{
var newCursorAbsoluteColumn = Math.Max(CursorAbsoluteColumn - 1, 0);
if (CursorRelativeColumn == 0)
{
return With(
out needsRedraw,
cursorAbsoluteColumn: newCursorAbsoluteColumn,
virtualCursorAbsoluteColumn: newCursorAbsoluteColumn,
startingColumn: Math.Max(StartingColumn - 1, 0));
}
else
{
return With(
out needsRedraw,
cursorAbsoluteColumn: newCursorAbsoluteColumn,
virtualCursorAbsoluteColumn: newCursorAbsoluteColumn);
}
}
public DisplayTextViewPort CursorRight(out bool needsRedraw)
{
var newCursorAbsoluteColumn = Math.Min(CursorAbsoluteColumn + 1, CurrentLineWidth);
if (CursorRelativeColumn == Width - 1)
{
return With(
out needsRedraw,
cursorAbsoluteColumn: newCursorAbsoluteColumn,
virtualCursorAbsoluteColumn: newCursorAbsoluteColumn,
startingColumn: StartingColumn + 1);
}
else
{
return With(
out needsRedraw,
cursorAbsoluteColumn: newCursorAbsoluteColumn,
virtualCursorAbsoluteColumn: newCursorAbsoluteColumn);
}
}
private DisplayTextViewPort SnapToLine(out bool needsRedraw)
{
var cursorAbsoluteColumn = Math.Min(VirtualCursorAbsoluteColumn, CurrentLineWidth);
if (cursorAbsoluteColumn < StartingColumn)
{
return With(
out needsRedraw,
startingColumn: cursorAbsoluteColumn,
cursorAbsoluteColumn: cursorAbsoluteColumn);
}
if (cursorAbsoluteColumn > StartingColumn + Width - 1)
{
return With(
out needsRedraw,
startingColumn: cursorAbsoluteColumn - Width + 1,
cursorAbsoluteColumn: cursorAbsoluteColumn);
}
return With(
out needsRedraw,
cursorAbsoluteColumn: cursorAbsoluteColumn);
}
public DisplayTextViewPort CursorUp(out bool needsRedraw)
{
bool changed1;
var result1 = CursorRelativeLine switch
{
0 => With(
out changed1,
startingLine: Math.Max(StartingLine - 1, 0),
cursorAbsoluteLine: Math.Max(StartingLine - 1, 0)),
_ => With(out changed1, cursorAbsoluteLine: CursorAbsoluteLine - 1),
};
var result = result1.SnapToLine(out var changed2);
needsRedraw = changed1 || changed2;
return result;
}
public DisplayTextViewPort CursorDown(out bool needsRedraw)
{
bool changed1;
var result1 = CursorRelativeLine switch
{
_ when CursorRelativeLine == Height - 1 =>
With(
out changed1,
startingLine: Math.Min(CursorAbsoluteLine + 1, Text.Lines.Count - 1) - Height + 1,
cursorAbsoluteLine: Math.Min(CursorAbsoluteLine + 1, Text.Lines.Count - 1)),
_ => With(
out changed1,
cursorAbsoluteLine: CursorAbsoluteLine + 1),
};
var result = result1.SnapToLine(out var changed2);
needsRedraw = changed1 || changed2;
return result;
}
internal DisplayTextViewPort PageDown(out bool needsRedraw)
{
var result1 = With(
out var changed1,
startingLine: Math.Min(StartingLine + Height, Text.Lines.Count - 1),
cursorAbsoluteLine: Math.Min(CursorAbsoluteLine + Height, Text.Lines.Count - 1));
var result = result1.SnapToLine(out var changed2);
needsRedraw = changed1 || changed2;
return result;
}
internal DisplayTextViewPort PageUp(out bool needsRedraw)
{
var result1 = With(
out var changed1,
startingLine: Math.Max(StartingLine - Height, 0),
cursorAbsoluteLine: Math.Max(CursorAbsoluteLine - Height, 0));
var result = result1.SnapToLine(out var changed2);
needsRedraw = changed1 || changed2;
return result;
}
public DisplayTextViewPort CursorHome(out bool needsRedraw)
{
return With(
out needsRedraw,
startingColumn: 0,
cursorAbsoluteColumn: 0,
virtualCursorAbsoluteColumn: 0);
}
public DisplayTextViewPort CursorEnd(out bool needsRedraw)
{
var lineWidth = Text.Lines[CursorAbsoluteLine].Width;
var toAdd = lineWidth - CursorAbsoluteColumn;
if (toAdd == 0)
{
needsRedraw = false;
return this;
}
if (CursorRelativeColumn + toAdd < Width)
{
return With(
out needsRedraw,
cursorAbsoluteColumn: CursorAbsoluteColumn + toAdd,
virtualCursorAbsoluteColumn: CursorAbsoluteColumn + toAdd);
}
return With(
out needsRedraw,
startingColumn: lineWidth - Width + 1,
cursorAbsoluteColumn: lineWidth,
virtualCursorAbsoluteColumn: lineWidth);
}
public void RenderTo(IOutputView view)
{
view.HideCursor();
for (var lineNumber = StartingLine; lineNumber < StartingLine + Height; lineNumber++)
{
view.MoveCursorTo(0, lineNumber - StartingLine);
if (lineNumber >= Text.Lines.Count)
{
view.WriteText(new string(' ', Width));
continue;
}
var line = Text.Lines[lineNumber];
var startsIn = StartingColumn;
foreach (var chunk in line.Chunks)
{
var left = Math.Max(0, startsIn);
var right = Math.Min(chunk.Width, startsIn + Width);
if (left < right)
{
view.SetStyle(chunk.Style);
view.WriteText(chunk.Text[left..right].ToString());
}
startsIn -= chunk.Width;
if (startsIn + Width <= 0)
{
break;
}
}
if (startsIn + Width > 0)
{
var numberOfSpaces = Math.Min(startsIn + Width, Width);
view.WriteText(new string(' ', numberOfSpaces));
}
}
view.MoveCursorTo(column: CursorRelativeColumn, line: CursorRelativeLine);
view.ShowCursor();
}
public DisplayTextViewPort With(
out bool changed,
int? width = null,
int? height = null,
int? startingColumn = null,
int? startingLine = null,
int? cursorAbsoluteColumn = null,
int? cursorAbsoluteLine = null,
int? virtualCursorAbsoluteColumn = null)
{
var widthValue = width ?? Width;
var heightValue = height ?? Height;
var startingColumnValue = startingColumn ?? StartingColumn;
var startingLineValue = startingLine ?? StartingLine;
var cursorAbsoluteColumnValue = cursorAbsoluteColumn ?? CursorAbsoluteColumn;
var cursorAbsoluteLineValue = cursorAbsoluteLine ?? CursorAbsoluteLine;
var virtualCursorAbsoluteColumnValue = virtualCursorAbsoluteColumn ?? VirtualCursorAbsoluteColumn;
if (widthValue == Width &&
heightValue == Height &&
startingColumnValue == StartingColumn &&
startingLineValue == StartingLine &&
cursorAbsoluteColumnValue == CursorAbsoluteColumn &&
cursorAbsoluteLineValue == CursorAbsoluteLine &&
virtualCursorAbsoluteColumnValue == VirtualCursorAbsoluteColumn)
{
changed = false;
return this;
}
changed = true;
return new DisplayTextViewPort(
text: Text,
width: widthValue,
height: heightValue,
startingColumn: startingColumnValue,
startingLine: startingLineValue,
cursorAbsoluteColumn: cursorAbsoluteColumnValue,
cursorAbsoluteLine: cursorAbsoluteLineValue,
virtualCursorAbsoluteColumn: virtualCursorAbsoluteColumnValue);
}
}
}

View File

@ -0,0 +1,13 @@
namespace MApplication
{
internal interface IOutputView
{
int Width { get; }
int Height { get; }
void MoveCursorTo(int column, int line);
void ShowCursor();
void HideCursor();
void SetStyle(Style style);
void WriteText(string s);
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Parser\Parser.csproj" />
</ItemGroup>
</Project>

130
MApplication/Program.cs Normal file
View File

@ -0,0 +1,130 @@
using Parser;
using System;
using System.IO;
namespace MApplication
{
internal class FileRenderer
{
private readonly IOutputView _outputView;
public FileRenderer(IOutputView outputView)
{
_outputView = outputView;
}
private static MParser CreateParser(ITextWindow window)
{
return new MParser(window);
}
private static SyntaxTree GetTree(string fileName)
{
var text = File.ReadAllText(fileName);
var window = new TextWindowWithNull(text, fileName);
var parser = CreateParser(window);
var tree = parser.Parse();
return tree;
}
public void RenderFile(string fileName)
{
var tree = GetTree(fileName);
var text = CodeProcessor.GetText(tree);
var viewPort = new DisplayTextViewPort(
text: text,
width: 80,
height: 24);
var needsRedraw = true;
while (true)
{
if (needsRedraw)
{
viewPort.RenderTo(_outputView);
}
_outputView.MoveCursorTo(viewPort.CursorRelativeColumn, viewPort.CursorRelativeLine);
var key = Console.ReadKey(intercept: true);
viewPort = key.Key switch
{
ConsoleKey.LeftArrow => viewPort.CursorLeft(out needsRedraw),
ConsoleKey.RightArrow => viewPort.CursorRight(out needsRedraw),
ConsoleKey.UpArrow => viewPort.CursorUp(out needsRedraw),
ConsoleKey.DownArrow => viewPort.CursorDown(out needsRedraw),
ConsoleKey.Home => viewPort.CursorHome(out needsRedraw),
ConsoleKey.End => viewPort.CursorEnd(out needsRedraw),
ConsoleKey.PageUp => viewPort.PageUp(out needsRedraw),
ConsoleKey.PageDown => viewPort.PageDown(out needsRedraw),
_ => viewPort,
};
if (key.Key == ConsoleKey.Q)
{
return;
}
}
}
}
class Program
{
private static readonly string BaseDirectory;
private const string BaseDirectoryMacOs = @"/Applications/MATLAB_R2017b.app/toolbox/matlab/";
private const string BaseDirectoryWindows = @"D:\Program Files\MATLAB\R2018a\toolbox\matlab\";
static Program()
{
switch (Environment.OSVersion.Platform)
{
case PlatformID.MacOSX:
case PlatformID.Unix:
BaseDirectory = BaseDirectoryMacOs;
break;
default:
BaseDirectory = BaseDirectoryWindows;
break;
}
}
private static Style GetStyle()
{
return new Style(
foregroundColor: Console.ForegroundColor,
backgroundColor: Console.BackgroundColor);
}
private static void SetStyle(Style style)
{
Console.BackgroundColor = style.BackgroundColor;
Console.ForegroundColor = style.ForegroundColor;
}
private static void PrintChunk(DisplayLineChunk chunk)
{
SetStyle(chunk.Style);
Console.Write(chunk.Text.ToString());
}
static void Main(string[] args)
{
var oldStyle = GetStyle();
var fileName = Path.Combine(
BaseDirectory,
"datatypes",
"@table",
"table.m");
var targetWidth = 80;
var targetHeight = 24;
var outputViewPort = new ConsoleWindowView(
startingColumn: (Console.WindowWidth - targetWidth) / 2,
startingLine: (Console.WindowHeight - targetHeight) / 2,
width: targetWidth,
height: targetHeight);
var renderer = new FileRenderer(outputViewPort);
renderer.RenderFile(fileName);
SetStyle(oldStyle);
}
}
}

31
MApplication/Style.cs Normal file
View File

@ -0,0 +1,31 @@
using System;
namespace MApplication
{
internal class Style
{
public Style(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor)
{
ForegroundColor = foregroundColor;
BackgroundColor = backgroundColor;
}
public ConsoleColor ForegroundColor { get; }
public ConsoleColor BackgroundColor { get; }
public static Style Color(ConsoleColor foregroundColor)
{
return new Style(foregroundColor, ConsoleColor.Black);
}
public static Style ColorWithBackGround(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor)
{
return new Style(foregroundColor, backgroundColor);
}
}
}

View File

@ -0,0 +1,53 @@
namespace MApplication
{
internal class StyleScheme
{
public StyleScheme(
Style defaultToken,
Style keyword,
Style controlKeyword,
Style trivia,
Style punctuation,
Style @operator,
Style identifier,
Style unquotedStringLiteral,
Style stringLiteral,
Style numberLiteral,
Style bracket)
{
DefaultToken = defaultToken;
Keyword = keyword;
ControlKeyword = controlKeyword;
Trivia = trivia;
Punctuation = punctuation;
Operator = @operator;
Identifier = identifier;
UnquotedStringLiteral = unquotedStringLiteral;
StringLiteral = stringLiteral;
NumberLiteral = numberLiteral;
Bracket = bracket;
}
public Style DefaultToken { get; }
public Style Keyword { get; }
public Style ControlKeyword { get; }
public Style Trivia { get; }
public Style Punctuation { get; }
public Style Operator { get; }
public Style Identifier { get; }
public Style UnquotedStringLiteral { get; }
public Style StringLiteral { get; }
public Style NumberLiteral { get; }
public Style Bracket { get; }
}
}

View File

@ -0,0 +1,27 @@
using System;
namespace MApplication
{
internal static class StyleSchemeFactory
{
private static StyleScheme _defaultScheme;
static StyleSchemeFactory()
{
_defaultScheme = new StyleScheme(
defaultToken: Style.Color(ConsoleColor.Gray),
keyword: Style.Color(ConsoleColor.Green),
controlKeyword: Style.Color(ConsoleColor.Yellow),
trivia: Style.Color(ConsoleColor.DarkGray),
punctuation: Style.Color(ConsoleColor.DarkBlue),
@operator: Style.Color(ConsoleColor.Cyan),
identifier: Style.Color(ConsoleColor.White),
unquotedStringLiteral: Style.Color(ConsoleColor.Blue),
stringLiteral: Style.Color(ConsoleColor.Magenta),
numberLiteral: Style.Color(ConsoleColor.DarkGreen),
bracket: Style.Color(ConsoleColor.DarkYellow));
}
public static StyleScheme GetDefaultScheme() => _defaultScheme;
}
}

View File

@ -19,7 +19,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Repl", "Repl\Repl.csproj", "{8FEDFE5D-3320-418F-88A6-09C1B51C4441}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Repl", "Repl\Repl.csproj", "{8FEDFE5D-3320-418F-88A6-09C1B51C4441}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MApplication", "MApplication\MApplication.csproj", "{A7EE271C-8822-43EA-BA13-5D6D5DC5B581}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -51,6 +53,10 @@ Global
{8FEDFE5D-3320-418F-88A6-09C1B51C4441}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FEDFE5D-3320-418F-88A6-09C1B51C4441}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FEDFE5D-3320-418F-88A6-09C1B51C4441}.Release|Any CPU.Build.0 = Release|Any CPU
{A7EE271C-8822-43EA-BA13-5D6D5DC5B581}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7EE271C-8822-43EA-BA13-5D6D5DC5B581}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7EE271C-8822-43EA-BA13-5D6D5DC5B581}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7EE271C-8822-43EA-BA13-5D6D5DC5B581}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE