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

View File

@ -1,14 +1,18 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq;
namespace MApplication namespace MApplication
{ {
internal class DisplayLine internal class DisplayLine
{ {
public ImmutableList<DisplayLineChunk> Chunks { get; }
public DisplayLine(ImmutableList<DisplayLineChunk> chunks) public DisplayLine(ImmutableList<DisplayLineChunk> chunks)
{ {
Chunks = 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 width,
int height, int height,
int startingColumn = 0, int startingColumn = 0,
int startingLine = 0) int startingLine = 0,
int cursorRelativeColumn = 0,
int cursorRelativeLine = 0)
{ {
Text = text; Text = text;
Width = width; Width = width;
Height = height; Height = height;
StartingColumn = startingColumn; StartingColumn = startingColumn;
StartingLine = startingLine; StartingLine = startingLine;
CursorRelativeColumn = cursorRelativeColumn;
CursorRelativeLine = cursorRelativeLine;
} }
public DisplayText Text { get; } public DisplayText Text { get; }
@ -28,8 +32,138 @@ namespace MApplication
public int StartingLine { get; } 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) public void RenderTo(IOutputView view)
{ {
view.HideCursor();
for (var lineNumber = StartingLine; lineNumber < StartingLine + Height; lineNumber++) for (var lineNumber = StartingLine; lineNumber < StartingLine + Height; lineNumber++)
{ {
view.MoveCursorTo(0, lineNumber - StartingLine); view.MoveCursorTo(0, lineNumber - StartingLine);
@ -63,32 +197,45 @@ namespace MApplication
view.WriteText(new string(' ', numberOfSpaces)); view.WriteText(new string(' ', numberOfSpaces));
} }
} }
view.MoveCursorTo(column: CursorRelativeColumn, line: CursorRelativeLine);
view.ShowCursor();
} }
public DisplayTextViewPort With( public DisplayTextViewPort With(
out bool changed,
int? width = null, int? width = null,
int? height = null, int? height = null,
int? startingColumn = null, int? startingColumn = null,
int? startingLine = null) int? startingLine = null,
int? cursorRelativeColumn = null,
int? cursorRelativeLine = null)
{ {
var widthValue = width ?? Width; var widthValue = width ?? Width;
var heightValue = height ?? Height; var heightValue = height ?? Height;
var startingColumnValue = startingColumn ?? StartingColumn; var startingColumnValue = startingColumn ?? StartingColumn;
var startingLineValue = startingLine ?? StartingLine; var startingLineValue = startingLine ?? StartingLine;
var cursorRelativeColumnValue = cursorRelativeColumn ?? CursorRelativeColumn;
var cursorRelativeLineValue = cursorRelativeLine ?? CursorRelativeLine;
if (widthValue == Width && if (widthValue == Width &&
heightValue == Height && heightValue == Height &&
startingColumnValue == StartingColumn && startingColumnValue == StartingColumn &&
startingLineValue == StartingLine) startingLineValue == StartingLine &&
cursorRelativeColumnValue == CursorRelativeColumn &&
cursorRelativeLineValue == CursorRelativeLine)
{ {
changed = false;
return this; return this;
} }
changed = true;
return new DisplayTextViewPort( return new DisplayTextViewPort(
text: Text, text: Text,
width: widthValue, width: widthValue,
height: heightValue, height: heightValue,
startingColumn: startingColumnValue, startingColumn: startingColumnValue,
startingLine: startingLineValue); startingLine: startingLineValue,
cursorRelativeColumn: cursorRelativeColumnValue,
cursorRelativeLine: cursorRelativeLineValue);
} }
} }
} }

View File

@ -5,6 +5,8 @@
int Width { get; } int Width { get; }
int Height { get; } int Height { get; }
void MoveCursorTo(int column, int line); void MoveCursorTo(int column, int line);
void ShowCursor();
void HideCursor();
void SetStyle(Style style); void SetStyle(Style style);
void WriteText(string s); void WriteText(string s);
} }

View File

@ -4,6 +4,80 @@ using System.IO;
namespace MApplication 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 class Program
{ {
private static readonly string BaseDirectory; 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() private static Style GetStyle()
{ {
return new Style( return new Style(
@ -57,56 +117,6 @@ namespace MApplication
Console.Write(chunk.Text.ToString()); 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) static void Main(string[] args)
{ {
var oldStyle = GetStyle(); var oldStyle = GetStyle();
@ -115,15 +125,15 @@ namespace MApplication
"datatypes", "datatypes",
"@table", "@table",
"table.m"); "table.m");
Console.CursorVisible = false; var targetWidth = 80;
RenderFile(fileName); var targetHeight = 24;
Console.CursorVisible = true; var outputViewPort = new ConsoleWindowView(
startingColumn: (Console.WindowWidth - targetWidth) / 2,
//foreach (var line in text.Lines) startingLine: (Console.WindowHeight - targetHeight) / 2,
//{ width: targetWidth,
// PrintLine(line); height: targetHeight);
// Console.WriteLine(); var renderer = new FileRenderer(outputViewPort);
//} renderer.RenderFile(fileName);
SetStyle(oldStyle); SetStyle(oldStyle);
} }