More cursor movements

This commit is contained in:
Alexander Luzgarev 2020-07-10 11:51:46 +02:00
parent ac43b77b1a
commit b8914311b4
5 changed files with 252 additions and 79 deletions

View File

@ -20,6 +20,11 @@ namespace MApplication
public int Height { get; }
public void HideCursor()
{
Console.CursorVisible = false;
}
public void MoveCursorTo(int column, int line)
{
Console.CursorLeft = StartingColumn + column;
@ -39,6 +44,11 @@ namespace MApplication
}
}
public void ShowCursor()
{
Console.CursorVisible = true;
}
public void WriteText(string s)
{
Console.Write(s);

View File

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

View File

@ -9,13 +9,17 @@ namespace MApplication
int width,
int height,
int startingColumn = 0,
int startingLine = 0)
int startingLine = 0,
int cursorRelativeColumn = 0,
int cursorRelativeLine = 0)
{
Text = text;
Width = width;
Height = height;
StartingColumn = startingColumn;
StartingLine = startingLine;
CursorRelativeColumn = cursorRelativeColumn;
CursorRelativeLine = cursorRelativeLine;
}
public DisplayText Text { get; }
@ -28,8 +32,138 @@ namespace MApplication
public int StartingLine { get; }
public int CursorRelativeColumn { get; }
public int CursorRelativeLine { get; }
public int CursorAbsoluteColumn => CursorRelativeColumn + StartingColumn;
public int CursorAbsoluteLine => CursorRelativeLine + StartingLine;
public int CurrentLineWidth => Text.Lines[CursorAbsoluteLine].Width;
public DisplayTextViewPort CursorLeft(out bool needsRedraw)
{
if (CursorRelativeColumn == 0)
{
return ShiftLeft(out needsRedraw);
}
else
{
return With(out needsRedraw, cursorRelativeColumn: CursorRelativeColumn - 1);
}
}
public DisplayTextViewPort CursorRight(out bool needsRedraw)
{
if (CursorRelativeColumn == Width - 1)
{
return ShiftRight(out needsRedraw);
}
else
{
return With(out needsRedraw, cursorRelativeColumn: CursorRelativeColumn + 1);
}
}
private DisplayTextViewPort SnapToLine(out bool needsRedraw)
{
if (CursorAbsoluteColumn > CurrentLineWidth)
{
needsRedraw = true;
var toSubtract = CursorAbsoluteColumn - CurrentLineWidth;
if (toSubtract < CursorRelativeColumn)
{
return With(out var _, cursorRelativeColumn: CursorRelativeColumn - toSubtract);
}
return With(
out var _,
startingColumn: StartingColumn - (toSubtract - CursorRelativeColumn),
cursorRelativeColumn: 0);
}
else
{
needsRedraw = false;
return this;
}
}
public DisplayTextViewPort CursorUp(out bool needsRedraw)
{
bool changed1;
var result1 = CursorRelativeLine switch
{
0 => ShiftUp(out changed1),
_ => With(out changed1, cursorRelativeLine: CursorRelativeLine - 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 => ShiftDown(out changed1),
_ => With(out changed1, cursorRelativeLine: CursorRelativeLine + 1),
};
var result = result1.SnapToLine(out var changed2);
needsRedraw = changed1 || changed2;
return result;
}
public DisplayTextViewPort CursorHome(out bool needsRedraw)
{
return With(out needsRedraw, startingColumn: 0, cursorRelativeColumn: 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, cursorRelativeColumn: CursorRelativeColumn + toAdd);
}
return With(
out needsRedraw,
startingColumn: StartingColumn + CursorRelativeColumn + toAdd - Width + 1,
cursorRelativeColumn: Width - 1);
}
public DisplayTextViewPort ShiftLeft(out bool needsRedraw)
{
return With(out needsRedraw, startingColumn: Math.Max(StartingColumn - 1, 0));
}
public DisplayTextViewPort ShiftRight(out bool needsRedraw)
{
return With(out needsRedraw, startingColumn: StartingColumn + 1);
}
public DisplayTextViewPort ShiftUp(out bool needsRedraw)
{
return With(out needsRedraw, startingLine: Math.Max(StartingLine - 1, 0));
}
public DisplayTextViewPort ShiftDown(out bool needsRedraw)
{
return With(out needsRedraw, startingLine: StartingLine + 1);
}
public void RenderTo(IOutputView view)
{
view.HideCursor();
for (var lineNumber = StartingLine; lineNumber < StartingLine + Height; lineNumber++)
{
view.MoveCursorTo(0, lineNumber - StartingLine);
@ -63,32 +197,45 @@ namespace MApplication
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? startingLine = null,
int? cursorRelativeColumn = null,
int? cursorRelativeLine = null)
{
var widthValue = width ?? Width;
var heightValue = height ?? Height;
var startingColumnValue = startingColumn ?? StartingColumn;
var startingLineValue = startingLine ?? StartingLine;
var cursorRelativeColumnValue = cursorRelativeColumn ?? CursorRelativeColumn;
var cursorRelativeLineValue = cursorRelativeLine ?? CursorRelativeLine;
if (widthValue == Width &&
heightValue == Height &&
startingColumnValue == StartingColumn &&
startingLineValue == StartingLine)
startingLineValue == StartingLine &&
cursorRelativeColumnValue == CursorRelativeColumn &&
cursorRelativeLineValue == CursorRelativeLine)
{
changed = false;
return this;
}
changed = true;
return new DisplayTextViewPort(
text: Text,
width: widthValue,
height: heightValue,
startingColumn: startingColumnValue,
startingLine: startingLineValue);
startingLine: startingLineValue,
cursorRelativeColumn: cursorRelativeColumnValue,
cursorRelativeLine: cursorRelativeLineValue);
}
}
}

View File

@ -5,6 +5,8 @@
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

@ -4,6 +4,80 @@ 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);
switch (key.Key)
{
case ConsoleKey.LeftArrow:
viewPort = viewPort.CursorLeft(out needsRedraw);
break;
case ConsoleKey.RightArrow:
viewPort = viewPort.CursorRight(out needsRedraw);
break;
case ConsoleKey.UpArrow:
viewPort = viewPort.CursorUp(out needsRedraw);
break;
case ConsoleKey.DownArrow:
viewPort = viewPort.CursorDown(out needsRedraw);
break;
case ConsoleKey.Home:
viewPort = viewPort.CursorHome(out needsRedraw);
break;
case ConsoleKey.End:
viewPort = viewPort.CursorEnd(out needsRedraw);
break;
}
}
}
}
class Program
{
private static readonly string BaseDirectory;
@ -24,20 +98,6 @@ namespace MApplication
}
}
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;
}
private static Style GetStyle()
{
return new Style(
@ -57,56 +117,6 @@ namespace MApplication
Console.Write(chunk.Text.ToString());
}
private static void PrintLine(DisplayLine line)
{
foreach (var chunk in line.Chunks)
{
PrintChunk(chunk);
}
}
static void RenderFile(string fileName)
{
var tree = GetTree(fileName);
var text = CodeProcessor.GetText(tree);
var viewPort = new DisplayTextViewPort(
text: text,
width: 80,
height: 24);
var targetWidth = 80;
var targetHeight = 24;
var outputViewPort = new ConsoleWindowView(
startingColumn: (Console.WindowWidth - targetWidth) / 2,
startingLine: (Console.WindowHeight - targetHeight) / 2,
width: targetWidth,
height: targetHeight);
while (true)
{
viewPort.RenderTo(outputViewPort);
var key = Console.ReadKey(intercept: true);
switch (key.Key)
{
case ConsoleKey.LeftArrow:
viewPort = viewPort.With(startingColumn: Math.Max(viewPort.StartingColumn - 1, 0));
break;
case ConsoleKey.RightArrow:
viewPort = viewPort.With(startingColumn: viewPort.StartingColumn + 1);
break;
case ConsoleKey.UpArrow:
viewPort = viewPort.With(startingLine: Math.Max(viewPort.StartingLine - 1, 0));
break;
case ConsoleKey.DownArrow:
viewPort = viewPort.With(startingLine: viewPort.StartingLine + 1);
break;
}
}
}
static void Main(string[] args)
{
var oldStyle = GetStyle();
@ -115,15 +125,15 @@ namespace MApplication
"datatypes",
"@table",
"table.m");
Console.CursorVisible = false;
RenderFile(fileName);
Console.CursorVisible = true;
//foreach (var line in text.Lines)
//{
// PrintLine(line);
// Console.WriteLine();
//}
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);
}