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