using Qrakhen.Qamp.Core; using Qrakhen.Qamp.Core.Execution; using Qrakhen.Qamp.Core.Tokenization; using System.Text; char[] Ignored = [ '\0', '\b' ]; Stack History = []; ConsoleKeyInfo input; bool useSyntaxHighlighting = false; (int x, int y) cursor = (0, 0); ConsoleCode code = ConsoleCode.Error; Runner runner = new Runner(new Options()); ConsoleInterface cli = new ConsoleInterface(Encoding.Default); do { /*Console.ForegroundColor = ConsoleColor.White; MemoryStream stream = new MemoryStream(); Console.Write(" <: "); cursor = Console.GetCursorPosition(); do { if (useSyntaxHighlighting) new ConsoleRenderer(stream).Render(cursor); input = Console.ReadKey(true); if (input.Modifiers == ConsoleModifiers.Control) { if (input.Key == ConsoleKey.H) { useSyntaxHighlighting = !useSyntaxHighlighting; Console.Write($"\n #: {nameof(useSyntaxHighlighting)} = {useSyntaxHighlighting}\n <: "); cursor = Console.GetCursorPosition(); } continue; } if (input.Key == ConsoleKey.LeftArrow) { if (stream.Position > 0) { stream.Position--; Console.CursorLeft--; } continue; } if (input.Key == ConsoleKey.RightArrow) { if (stream.Position < stream.Length) { stream.Position++; Console.CursorLeft++; } continue; } if (input.Key == ConsoleKey.Backspace && stream.Position > 0) { Console.CursorLeft -= 1; Console.Write(' '); if (!useSyntaxHighlighting) Console.CursorLeft -= 1; //stream.Position--; //stream.SetLength(stream.Position); stream.Remove(stream.Position - 1, 1); } else if (input.Key == ConsoleKey.Enter && input.Modifiers == ConsoleModifiers.Shift) { if (!useSyntaxHighlighting) Console.Write("\n : "); stream.Insert(Encoding.Default.GetBytes(Environment.NewLine)); } else if (Ignored.IndexOf(input.KeyChar) < 0) { if (!useSyntaxHighlighting) Console.Write(input.KeyChar); stream.Insert(Encoding.Default.GetBytes([input.KeyChar], 0, 1)); } } while (input.Key != ConsoleKey.Enter || input.Modifiers == ConsoleModifiers.Shift);*/ try { code = cli.Read(out Stream? stream); if (code == ConsoleCode.OK) { if (stream == null) throw new QampException($"Stream from CLI was null {code}"); Console.WriteLine(); runner.Run(stream); } if (code == ConsoleCode.Error) throw new QampException($"CLI returned {code}"); } catch (QampException e) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($" !> {e.Message}"); if (e.StackTrace != null) { Console.Write($" ! "); Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); } } catch (Exception e) { Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine($" !? {e.Message}"); if (e.StackTrace != null) { Console.Write($" ! "); Console.WriteLine(string.Join("\n ! ", e.StackTrace.Split('\n'))); } } } while(code != ConsoleCode.Exit); class ConsoleInterface { private const string SYMBOL_INPUT = " <: "; private const string SYMBOL_INPUT_CONTINUE = " : "; private readonly List _buffer = []; private readonly Stack _history = []; private readonly Encoding _encoding; private int _position; private (int x, int y) _origin; private (int x, int y) _cursorPosition => Console.GetCursorPosition(); private int _cursorOffset => SYMBOL_INPUT.Length; private int _cursorLeft { get => Console.CursorLeft; set => Console.CursorLeft = value; } private int _cursorTop { get => Console.CursorTop; set => Console.CursorTop = value; } public bool UseSyntaxHighlighting { get; set; } = false; public ConsoleInterface(Encoding encoding) { _encoding = encoding; } private void Write(char c) => Console.Write(c); private void Write(string str) => Console.Write(str); private void SetCursor((int x, int y) position) => Console.SetCursorPosition(position.x, position.y); private void SetColor(ConsoleColor color, ConsoleColor background = ConsoleColor.Black) { Console.ForegroundColor = color; Console.BackgroundColor = background; } private void Move(int x, int y = 0) { _position = Math.Min(_buffer.Count, Math.Max(0, _position + x)); _cursorLeft -= 1; //???? } private void ClearLine() { int left = _cursorLeft; while (_cursorLeft < Console.BufferWidth - 1) Write(' '); _cursorLeft = left; } private void Print((int x, int y) origin, (int x, int y)? remain = null) { SetColor(ConsoleColor.White); SetCursor(origin); Write(" <: "); foreach (var c in _buffer) { if (c == '\n') { ClearLine(); Write("\n : "); } else { Write(c); } } ClearLine(); if (remain.HasValue) SetCursor(remain.Value); } private Stream Dispatch() { var stream = new MemoryStream(); var data = _buffer.ToArray(); stream.Write(_encoding.GetBytes(data)); _history.Push(data); _buffer.Clear(); return stream; } public ConsoleCode Read(out Stream? stream) { stream = null; ConsoleKeyInfo input; _origin = _cursorPosition; _position = 0; Print(_origin); do { if (UseSyntaxHighlighting) new ConsoleRenderer(new MemoryStream(_encoding.GetBytes(_buffer.ToArray()))).Render(_origin); // ~ so efficient ~ XD Print(_origin, _cursorPosition); input = Console.ReadKey(true); if (input.Modifiers == ConsoleModifiers.Control) { if (input.Key == ConsoleKey.C) return ConsoleCode.Exit; if (input.Key == ConsoleKey.H) { UseSyntaxHighlighting = !UseSyntaxHighlighting; Write($"\n #: {nameof(UseSyntaxHighlighting)} = {UseSyntaxHighlighting}\n <: "); _origin = _cursorPosition; } if (input.Key == ConsoleKey.LeftArrow) { } continue; } if (input.Key == ConsoleKey.LeftArrow) { if (_position > 0) { _position--; _cursorLeft--; } continue; } if (input.Key == ConsoleKey.RightArrow) { if (_position < _buffer.Count) { _position++; _cursorLeft++; } continue; } if (input.Key == ConsoleKey.Backspace) { if (_position > 0) { _cursorLeft--; _buffer.RemoveRange(--_position, 1); } continue; } else if (input.Check(ConsoleKey.Enter, ConsoleModifiers.Shift)) { _buffer.Insert(_position++, '\n'); _cursorLeft = _cursorOffset; _cursorTop++; continue; } else { _buffer.Insert(_position++, input.KeyChar); _cursorLeft++; } } while (!input.Check(ConsoleKey.Enter, ConsoleModifiers.None, true)); stream = Dispatch(); return ConsoleCode.OK; } } enum ConsoleCode { Error = -1, OK = 0, Exit = 1 } class ConsoleRenderer { private readonly IReader _reader; private readonly Stream _stream; public ConsoleRenderer(Stream stream) { _stream = new MemoryStream(); stream.Position = 0; stream.CopyTo(_stream); _reader = new Reader(_stream); } public void Render((int x, int y) position) { Console.CursorVisible = false; Console.SetCursorPosition(position.x, position.y); List tokens = []; while (!_reader.Done) { tokens.Add(_reader.NextToken(true)); } _stream.Position = 0; foreach (var token in tokens) { ConsoleColor color = ConsoleColor.Gray; if (token.Type.IsBoolean()) color = ConsoleColor.Blue; if (token.Type.IsString()) color = ConsoleColor.Red; if (token.Type.IsNumber()) color = ConsoleColor.DarkCyan; if (token.Type.IsOperator()) color = ConsoleColor.DarkGreen; if (token.Type.IsBracket()) color = ConsoleColor.Yellow; if (token.Type.IsIdentifier()) color = ConsoleColor.White; if (token.Type.IsControl()) color = ConsoleColor.DarkYellow; if (token.Type == TokenType.Error) color = ConsoleColor.DarkRed; Console.ForegroundColor = color; byte[] buffer = new byte[token.Span.Length]; _stream.ReadExactly(buffer, 0, (int)token.Span.Length); string str = Encoding.Default.GetString(buffer); Console.Write(str); Console.ForegroundColor = ConsoleColor.White; if (token.Type == TokenType.NewLine) Console.Write(" : "); } Console.ForegroundColor = ConsoleColor.White; Console.CursorVisible = true; } } public static class ConsoleExtensions { public static bool Check(this ConsoleKeyInfo keyInfo, ConsoleKey key, ConsoleModifiers modifier = default, bool exactModifier = false) { return ((exactModifier ? keyInfo.Modifiers == modifier : (keyInfo.Modifiers & modifier) == modifier) && keyInfo.Key == key); } }