More cursor movements
This commit is contained in:
parent
ac43b77b1a
commit
b8914311b4
@ -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);
|
||||||
|
@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user