From 70a1570441263d5a8a8b669be726318cae559954 Mon Sep 17 00:00:00 2001 From: sinaioutlander <49360850+sinaioutlander@users.noreply.github.com> Date: Wed, 11 Nov 2020 00:16:01 +1100 Subject: [PATCH] cleanup and refactor C# lexer classes --- src/Console/AutoCompleter.cs | 2 +- src/Console/CSharpLexer.cs | 257 ++++++++++++++++++++++-------- src/Console/CodeEditor.cs | 110 +++++-------- src/Console/Lexer/CommentMatch.cs | 15 +- src/Console/Lexer/InputLexer.cs | 201 ----------------------- src/Console/Lexer/KeywordMatch.cs | 39 ++--- src/Console/Lexer/Matcher.cs | 11 +- src/Console/Lexer/NumberMatch.cs | 6 +- src/Console/Lexer/StringMatch.cs | 23 +-- src/Console/Lexer/SymbolMatch.cs | 75 ++------- src/Console/Suggestion.cs | 63 +++----- src/UI/UIFactory.cs | 9 +- src/UnityExplorer.csproj | 3 +- 13 files changed, 308 insertions(+), 506 deletions(-) delete mode 100644 src/Console/Lexer/InputLexer.cs diff --git a/src/Console/AutoCompleter.cs b/src/Console/AutoCompleter.cs index a9d43e3..39e7254 100644 --- a/src/Console/AutoCompleter.cs +++ b/src/Console/AutoCompleter.cs @@ -133,7 +133,7 @@ namespace UnityExplorer.Console { var editor = ConsolePage.Instance.m_codeEditor; - var textGen = editor.inputText.cachedTextGenerator; + var textGen = editor.InputText.cachedTextGenerator; //if (textGen.characters.Count < 1) // return; diff --git a/src/Console/CSharpLexer.cs b/src/Console/CSharpLexer.cs index 96662f8..87b653c 100644 --- a/src/Console/CSharpLexer.cs +++ b/src/Console/CSharpLexer.cs @@ -1,19 +1,45 @@ using System.Collections.Generic; using System.Text; -using UnityExplorer.Console.Lexer; using UnityEngine; +using UnityExplorer.Console.Lexer; namespace UnityExplorer.Console { - public static class CSharpLexer + public struct LexerMatchInfo { - public static char indentIncreaseCharacter = '{'; - public static char indentDecreaseCharacter = '}'; + public int startIndex; + public int endIndex; + public string htmlColor; + } - public static string delimiterSymbols = "[ ] ( ) { } ; : , ."; + public enum DelimiterType + { + Start, + End, + }; + public class CSharpLexer + { + private string inputString; + private readonly Matcher[] matchers; + private readonly HashSet startDelimiters; + private readonly HashSet endDelimiters; + private int currentIndex; + private int currentLookaheadIndex; + + public char Current { get; private set; } = ' '; + public char Previous { get; private set; } = ' '; + + public bool EndOfStream => currentLookaheadIndex >= inputString.Length; + + public static char indentOpen = '{'; + public static char indentClose = '}'; private static readonly StringBuilder indentBuilder = new StringBuilder(); + public static char[] delimiters = new[] + { + '[', ']', '(', ')', '{', '}', ';', ':', ',', '.' + }; public static CommentMatch commentMatcher = new CommentMatch(); public static SymbolMatch symbolMatcher = new SymbolMatch(); public static NumberMatch numberMatcher = new NumberMatch(); @@ -22,80 +48,109 @@ namespace UnityExplorer.Console public static KeywordMatch validKeywordMatcher = new KeywordMatch { highlightColor = new Color(0.33f, 0.61f, 0.83f, 1.0f), - keywords = @"add as ascending await bool break by byte - case catch char checked const continue decimal default descending do dynamic - else equals false finally float for foreach from global goto group - if in int into is join let lock long new null object on orderby out - ref remove return sbyte select short sizeof stackalloc string - switch throw true try typeof uint ulong ushort - var where while yield" + Keywords = new[] { "add", "as", "ascending", "await", "bool", "break", "by", "byte", +"case", "catch", "char", "checked", "const", "continue", "decimal", "default", "descending", "do", "dynamic", +"else", "equals", "false", "finally", "float", "for", "foreach", "from", "global", "goto", "group", +"if", "in", "int", "into", "is", "join", "let", "lock", "long", "new", "null", "object", "on", "orderby", "out", +"ref", "remove", "return", "sbyte", "select", "short", "sizeof", "stackalloc", "string", +"switch", "throw", "true", "try", "typeof", "uint", "ulong", "ushort", "var", "where", "while", "yield" } }; public static KeywordMatch invalidKeywordMatcher = new KeywordMatch() { highlightColor = new Color(0.95f, 0.10f, 0.10f, 1.0f), - keywords = @"abstract async base class delegate enum explicit extern fixed get - implicit interface internal namespace operator override params private protected public - using partial readonly sealed set static struct this unchecked unsafe value virtual volatile void" + Keywords = new[] { "abstract", "async", "base", "class", "delegate", "enum", "explicit", "extern", "fixed", "get", +"implicit", "interface", "internal", "namespace", "operator", "override", "params", "private", "protected", "public", +"using", "partial", "readonly", "sealed", "set", "static", "struct", "this", "unchecked", "unsafe", "value", "virtual", "volatile", "void" } }; - private static char[] delimiterSymbolCache = null; - internal static char[] DelimiterSymbols + // ~~~~~~~ ctor ~~~~~~~ + + public CSharpLexer() { - get + startDelimiters = new HashSet(delimiters); + endDelimiters = new HashSet(delimiters); + + this.matchers = new Matcher[] { - if (delimiterSymbolCache == null) + commentMatcher, + symbolMatcher, + numberMatcher, + stringMatcher, + validKeywordMatcher, + invalidKeywordMatcher, + }; + + foreach (Matcher lexer in matchers) + { + foreach (char c in lexer.StartChars) { - string[] symbols = delimiterSymbols.Split(' '); - - int count = 0; - - for (int i = 0; i < symbols.Length; i++) - { - if (symbols[i].Length == 1) - { - count++; - } - } - - delimiterSymbolCache = new char[count]; - - for (int i = 0, index = 0; i < symbols.Length; i++) - { - if (symbols[i].Length == 1) - { - delimiterSymbolCache[index] = symbols[i][0]; - index++; - } - } + if (!startDelimiters.Contains(c)) + startDelimiters.Add(c); + } + + foreach (char c in lexer.EndChars) + { + if (!endDelimiters.Contains(c)) + endDelimiters.Add(c); } - return delimiterSymbolCache; } } - private static Matcher[] matchers = null; - internal static Matcher[] Matchers - { - get - { - if (matchers == null) - { - List matcherList = new List - { - commentMatcher, - symbolMatcher, - numberMatcher, - stringMatcher, - validKeywordMatcher, - invalidKeywordMatcher, - }; + // ~~~~~~~ Lex Matching ~~~~~~~ - matchers = matcherList.ToArray(); + public IEnumerable GetMatches(string input) + { + if (input == null || matchers == null || matchers.Length == 0) + { + yield break; + } + + inputString = input; + Current = ' '; + Previous = ' '; + currentIndex = 0; + currentLookaheadIndex = 0; + + while (!EndOfStream) + { + bool didMatchLexer = false; + + ReadWhiteSpace(); + + foreach (Matcher matcher in matchers) + { + int startIndex = currentIndex; + + bool isMatched = matcher.IsMatch(this); + + if (isMatched) + { + int endIndex = currentIndex; + + didMatchLexer = true; + + yield return new LexerMatchInfo + { + startIndex = startIndex, + endIndex = endIndex, + htmlColor = matcher.HexColor, + }; + + break; + } + } + + if (!didMatchLexer) + { + ReadNext(); + Commit(); } - return matchers; } } + // ~~~~~~~ Indent ~~~~~~~ + public static string GetIndentForInput(string input, int indent, out int caretPosition) { indentBuilder.Clear(); @@ -123,14 +178,14 @@ namespace UnityExplorer.Console { continue; } - else if (!stringState && input[i] == indentIncreaseCharacter) + else if (!stringState && input[i] == indentOpen) { - indentBuilder.Append(indentIncreaseCharacter); + indentBuilder.Append(indentOpen); indent++; } - else if (!stringState && input[i] == indentDecreaseCharacter) + else if (!stringState && input[i] == indentClose) { - indentBuilder.Append(indentDecreaseCharacter); + indentBuilder.Append(indentClose); indent--; } else @@ -177,5 +232,77 @@ namespace UnityExplorer.Console return indent; } + + // Lexer reading + + public char ReadNext() + { + if (EndOfStream) + { + return '\0'; + } + + Previous = Current; + + Current = inputString[currentLookaheadIndex]; + currentLookaheadIndex++; + + return Current; + } + + public void Rollback(int amount = -1) + { + if (amount == -1) + { + currentLookaheadIndex = currentIndex; + } + else + { + if (currentLookaheadIndex > currentIndex) + { + currentLookaheadIndex -= amount; + } + } + + int previousIndex = currentLookaheadIndex - 1; + + if (previousIndex >= inputString.Length) + { + Previous = inputString[inputString.Length - 1]; + } + else if (previousIndex >= 0) + { + Previous = inputString[previousIndex]; + } + else + { + Previous = ' '; + } + } + + public void Commit() + { + currentIndex = currentLookaheadIndex; + } + + public bool IsSpecialSymbol(char character, DelimiterType position = DelimiterType.Start) + { + if (position == DelimiterType.Start) + { + return startDelimiters.Contains(character); + } + + return endDelimiters.Contains(character); + } + + private void ReadWhiteSpace() + { + while (char.IsWhiteSpace(ReadNext()) == true) + { + Commit(); + } + + Rollback(); + } } -} +} \ No newline at end of file diff --git a/src/Console/CodeEditor.cs b/src/Console/CodeEditor.cs index 2b129a8..c8d1cc0 100644 --- a/src/Console/CodeEditor.cs +++ b/src/Console/CodeEditor.cs @@ -18,22 +18,21 @@ using UnhollowerRuntimeLib; namespace UnityExplorer.Console { + // Handles most of the UI side of the C# console, including syntax highlighting. + public class CodeEditor { - private readonly InputLexer inputLexer = new InputLexer(); - public InputField InputField { get; internal set; } + public Text InputText { get; internal set; } + public int CurrentIndent { get; private set; } - public Text inputText; private Text inputHighlightText; private Image background; private Image scrollbar; - public int LineCount { get; private set; } - public int CurrentLine { get; private set; } - public int CurrentIndent { get; private set; } - - private static readonly StringBuilder highlightedBuilder = new StringBuilder(4096); + public string HighlightedText => inputHighlightText.text; + private readonly CSharpLexer highlightLexer; + private readonly StringBuilder sbHighlight; private static readonly KeyCode[] onFocusKeys = { @@ -41,28 +40,6 @@ namespace UnityExplorer.Console KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow }; - public string HighlightedText => inputHighlightText.text; - - public string Text - { - get { return InputField.text; } - set - { - if (!string.IsNullOrEmpty(value)) - { - InputField.text = value; - inputHighlightText.text = value; - } - else - { - InputField.text = string.Empty; - inputHighlightText.text = string.Empty; - } - - //inputText.ForceMeshUpdate(false); - } - } - internal const string STARTUP_TEXT = @"Welcome to the UnityExplorer C# Console. The following helper methods are available: @@ -86,14 +63,14 @@ The following helper methods are available: public CodeEditor() { - ConstructUI(); + sbHighlight = new StringBuilder(); + highlightLexer = new CSharpLexer(); - ApplyTheme(); - inputLexer.UseMatchers(CSharpLexer.DelimiterSymbols, CSharpLexer.Matchers); + ConstructUI(); // subscribe to text input changing #if CPP - InputField.onValueChanged.AddListener(new Action((string s) => { OnInputChanged(); })); + InputField.onValueChanged.AddListener(new Action((string s) => { OnInputChanged(s); })); #else this.InputField.onValueChanged.AddListener((string s) => { OnInputChanged(s); }); #endif @@ -166,10 +143,10 @@ The following helper methods are available: { char character = newText[i]; - if (character == CSharpLexer.indentIncreaseCharacter) + if (character == CSharpLexer.indentOpen) CurrentIndent++; - if (character == CSharpLexer.indentDecreaseCharacter) + if (character == CSharpLexer.indentClose) CurrentIndent--; } @@ -183,33 +160,33 @@ The following helper methods are available: { int offset = 0; - highlightedBuilder.Length = 0; + sbHighlight.Length = 0; - foreach (LexerMatchInfo match in inputLexer.LexInputString(inputText)) + foreach (LexerMatchInfo match in highlightLexer.GetMatches(inputText)) { for (int i = offset; i < match.startIndex; i++) { - highlightedBuilder.Append(inputText[i]); + sbHighlight.Append(inputText[i]); } - highlightedBuilder.Append($"{match.htmlColor}"); + sbHighlight.Append($"{match.htmlColor}"); for (int i = match.startIndex; i < match.endIndex; i++) { - highlightedBuilder.Append(inputText[i]); + sbHighlight.Append(inputText[i]); } - highlightedBuilder.Append(CLOSE_COLOR_TAG); + sbHighlight.Append(CLOSE_COLOR_TAG); offset = match.endIndex; } for (int i = offset; i < inputText.Length; i++) { - highlightedBuilder.Append(inputText[i]); + sbHighlight.Append(inputText[i]); } - inputText = highlightedBuilder.ToString(); + inputText = sbHighlight.ToString(); return inputText; } @@ -242,8 +219,8 @@ The following helper methods are available: } // check if should add auto-close } - int numOpen = InputField.text.Where(x => x == CSharpLexer.indentIncreaseCharacter).Count(); - int numClose = InputField.text.Where(x => x == CSharpLexer.indentDecreaseCharacter).Count(); + int numOpen = InputField.text.Where(x => x == CSharpLexer.indentOpen).Count(); + int numClose = InputField.text.Where(x => x == CSharpLexer.indentClose).Count(); if (numOpen > numClose) { @@ -263,13 +240,13 @@ The following helper methods are available: // Update line column and indent positions UpdateIndent(InputField.text); - inputText.text = InputField.text; + InputText.text = InputField.text; //inputText.SetText(InputField.text, true); - inputText.Rebuild(CanvasUpdate.Prelayout); + InputText.Rebuild(CanvasUpdate.Prelayout); InputField.ForceLabelUpdate(); InputField.Rebuild(CanvasUpdate.Prelayout); - OnInputChanged(inputText.text, true); + OnInputChanged(InputText.text, true); } private string GetAutoIndentTab(int amount) @@ -284,26 +261,6 @@ The following helper methods are available: return tab; } - // ============== Theme ============== // - - private static Color backgroundColor = new Color32(37, 37, 37, 255); - private static Color scrollbarColor = new Color32(45, 50, 50, 255); - - private void ApplyTheme() - { - var highlightTextRect = inputHighlightText.GetComponent(); - highlightTextRect.anchorMin = Vector2.zero; - highlightTextRect.anchorMax = Vector2.one; - highlightTextRect.offsetMin = Vector2.zero; - highlightTextRect.offsetMax = Vector2.zero; - - InputField.caretColor = Color.white; - inputText.color = new Color(1, 1, 1, 0.51f); - inputHighlightText.color = Color.white; - background.color = backgroundColor; - scrollbar.color = scrollbarColor; - } - // ========== UI CONSTRUCTION =========== // public void ConstructUI() @@ -523,14 +480,27 @@ The following helper methods are available: mainTextInput.font = UIManager.ConsoleFont; highlightTextInput.font = UIManager.ConsoleFont; + // reset this after formatting finalized + highlightTextRect.anchorMin = Vector2.zero; + highlightTextRect.anchorMax = Vector2.one; + highlightTextRect.offsetMin = Vector2.zero; + highlightTextRect.offsetMax = Vector2.zero; + // assign references this.InputField = inputField; - this.inputText = mainTextInput; + this.InputText = mainTextInput; this.inputHighlightText = highlightTextInput; this.background = mainBgImage; this.scrollbar = scrollImage; + + // set some colors + InputField.caretColor = Color.white; + InputText.color = new Color(1, 1, 1, 0.51f); + inputHighlightText.color = Color.white; + background.color = new Color32(37, 37, 37, 255); + scrollbar.color = new Color32(45, 50, 50, 255); } } } diff --git a/src/Console/Lexer/CommentMatch.cs b/src/Console/Lexer/CommentMatch.cs index e5f019c..d096993 100644 --- a/src/Console/Lexer/CommentMatch.cs +++ b/src/Console/Lexer/CommentMatch.cs @@ -3,7 +3,7 @@ using UnityEngine; namespace UnityExplorer.Console.Lexer { - public sealed class CommentMatch : Matcher + public class CommentMatch : Matcher { public string lineCommentStart = @"//"; public string blockCommentStart = @"/*"; @@ -12,9 +12,9 @@ namespace UnityExplorer.Console.Lexer public override Color HighlightColor => new Color(0.34f, 0.65f, 0.29f, 1.0f); public override IEnumerable StartChars => new char[] { lineCommentStart[0], blockCommentStart[0] }; public override IEnumerable EndChars => new char[] { blockCommentEnd[0] }; - public override bool IsImplicitMatch(InputLexer lexer) => IsMatch(lexer, lineCommentStart) || IsMatch(lexer, blockCommentStart); + public override bool IsImplicitMatch(CSharpLexer lexer) => IsMatch(lexer, lineCommentStart) || IsMatch(lexer, blockCommentStart); - private bool IsMatch(InputLexer lexer, string commentType) + private bool IsMatch(CSharpLexer lexer, string commentType) { if (!string.IsNullOrEmpty(commentType)) { @@ -32,11 +32,8 @@ namespace UnityExplorer.Console.Lexer if (match) { - // Read until end - while (!IsEndLineOrEndFile(lexer, lexer.ReadNext())) - { - ; - } + // Read until end of line or file + while (!IsEndLineOrEndFile(lexer, lexer.ReadNext())) { } return true; } @@ -44,6 +41,6 @@ namespace UnityExplorer.Console.Lexer return false; } - private bool IsEndLineOrEndFile(InputLexer lexer, char character) => lexer.EndOfStream || character == '\n' || character == '\r'; + private bool IsEndLineOrEndFile(CSharpLexer lexer, char character) => lexer.EndOfStream || character == '\n' || character == '\r'; } } diff --git a/src/Console/Lexer/InputLexer.cs b/src/Console/Lexer/InputLexer.cs deleted file mode 100644 index b329880..0000000 --- a/src/Console/Lexer/InputLexer.cs +++ /dev/null @@ -1,201 +0,0 @@ -using System.Collections.Generic; - -namespace UnityExplorer.Console.Lexer -{ - public struct LexerMatchInfo - { - public int startIndex; - public int endIndex; - public string htmlColor; - } - - public enum SpecialCharacterPosition - { - Start, - End, - }; - - public class InputLexer - { - private string inputString = null; - private Matcher[] matchers = null; - private readonly HashSet specialStartSymbols = new HashSet(); - private readonly HashSet specialEndSymbols = new HashSet(); - private int currentIndex = 0; - private int currentLookaheadIndex = 0; - - private char current = ' '; - public char Previous { get; private set; } = ' '; - - public bool EndOfStream - { - get { return currentLookaheadIndex >= inputString.Length; } - } - - public void UseMatchers(char[] delimiters, Matcher[] matchers) - { - this.matchers = matchers; - - specialStartSymbols.Clear(); - specialEndSymbols.Clear(); - - if (delimiters != null) - { - foreach (char character in delimiters) - { - if (!specialStartSymbols.Contains(character)) - { - specialStartSymbols.Add(character); - } - - if (!specialEndSymbols.Contains(character)) - { - specialEndSymbols.Add(character); - } - } - } - - if (matchers != null) - { - foreach (Matcher lexer in matchers) - { - foreach (char special in lexer.StartChars) - { - if (!specialStartSymbols.Contains(special)) - { - specialStartSymbols.Add(special); - } - } - - foreach (char special in lexer.EndChars) - { - if (!specialEndSymbols.Contains(special)) - { - specialEndSymbols.Add(special); - } - } - } - } - } - - public IEnumerable LexInputString(string input) - { - if (input == null || matchers == null || matchers.Length == 0) - { - yield break; - } - - inputString = input; - current = ' '; - Previous = ' '; - currentIndex = 0; - currentLookaheadIndex = 0; - - while (!EndOfStream) - { - bool didMatchLexer = false; - - ReadWhiteSpace(); - - foreach (Matcher matcher in matchers) - { - int startIndex = currentIndex; - - bool isMatched = matcher.IsMatch(this); - - if (isMatched) - { - int endIndex = currentIndex; - - didMatchLexer = true; - - yield return new LexerMatchInfo - { - startIndex = startIndex, - endIndex = endIndex, - htmlColor = matcher.HexColor, - }; - - break; - } - } - - if (!didMatchLexer) - { - ReadNext(); - Commit(); - } - } - } - - public char ReadNext() - { - if (EndOfStream) - { - return '\0'; - } - - Previous = current; - - current = inputString[currentLookaheadIndex]; - currentLookaheadIndex++; - - return current; - } - - public void Rollback(int amount = -1) - { - if (amount == -1) - { - currentLookaheadIndex = currentIndex; - } - else - { - if (currentLookaheadIndex > currentIndex) - { - currentLookaheadIndex -= amount; - } - } - - int previousIndex = currentLookaheadIndex - 1; - - if (previousIndex >= inputString.Length) - { - Previous = inputString[inputString.Length - 1]; - } - else if (previousIndex >= 0) - { - Previous = inputString[previousIndex]; - } - else - { - Previous = ' '; - } - } - - public void Commit() - { - currentIndex = currentLookaheadIndex; - } - - public bool IsSpecialSymbol(char character, SpecialCharacterPosition position = SpecialCharacterPosition.Start) - { - if (position == SpecialCharacterPosition.Start) - { - return specialStartSymbols.Contains(character); - } - - return specialEndSymbols.Contains(character); - } - - private void ReadWhiteSpace() - { - while (char.IsWhiteSpace(ReadNext()) == true) - { - Commit(); - } - - Rollback(); - } - } -} \ No newline at end of file diff --git a/src/Console/Lexer/KeywordMatch.cs b/src/Console/Lexer/KeywordMatch.cs index 1a8e65a..b944526 100644 --- a/src/Console/Lexer/KeywordMatch.cs +++ b/src/Console/Lexer/KeywordMatch.cs @@ -3,23 +3,22 @@ using UnityEngine; namespace UnityExplorer.Console.Lexer { - public sealed class KeywordMatch : Matcher + // I use two different KeywordMatch instances (valid and invalid). + // This class just contains common implementations. + public class KeywordMatch : Matcher { - public string keywords; + public string[] Keywords; public override Color HighlightColor => highlightColor; public Color highlightColor; private readonly HashSet shortlist = new HashSet(); private readonly Stack removeList = new Stack(); - public string[] keywordCache = null; - public override bool IsImplicitMatch(InputLexer lexer) + public override bool IsImplicitMatch(CSharpLexer lexer) { - BuildKeywordCache(); - if (!char.IsWhiteSpace(lexer.Previous) && - !lexer.IsSpecialSymbol(lexer.Previous, SpecialCharacterPosition.End)) + !lexer.IsSpecialSymbol(lexer.Previous, DelimiterType.End)) { return false; } @@ -29,11 +28,11 @@ namespace UnityExplorer.Console.Lexer int currentIndex = 0; char currentChar = lexer.ReadNext(); - for (int i = 0; i < keywordCache.Length; i++) + for (int i = 0; i < Keywords.Length; i++) { - if (keywordCache[i][0] == currentChar) + if (Keywords[i][0] == currentChar) { - shortlist.Add(keywordCache[i]); + shortlist.Add(Keywords[i]); } } @@ -54,7 +53,7 @@ namespace UnityExplorer.Console.Lexer currentIndex++; if (char.IsWhiteSpace(currentChar) || - lexer.IsSpecialSymbol(currentChar, SpecialCharacterPosition.Start)) + lexer.IsSpecialSymbol(currentChar, DelimiterType.Start)) { RemoveLongStrings(currentIndex); lexer.Rollback(1); @@ -94,23 +93,5 @@ namespace UnityExplorer.Console.Lexer shortlist.Remove(removeList.Pop()); } } - - private void BuildKeywordCache() - { - if (keywordCache == null) - { - string[] kwSplit = keywords.Split(' '); - - List list = new List(); - foreach (string kw in kwSplit) - { - if (!string.IsNullOrEmpty(kw) && kw.Length > 0) - { - list.Add(kw); - } - } - keywordCache = list.ToArray(); - } - } } } diff --git a/src/Console/Lexer/Matcher.cs b/src/Console/Lexer/Matcher.cs index 7f58df6..9f626f8 100644 --- a/src/Console/Lexer/Matcher.cs +++ b/src/Console/Lexer/Matcher.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using UnityExplorer.Unstrip; using UnityEngine; +using System.Linq; namespace UnityExplorer.Console.Lexer { @@ -9,14 +10,14 @@ namespace UnityExplorer.Console.Lexer public abstract Color HighlightColor { get; } public string HexColor => htmlColor ?? (htmlColor = ""); - private string htmlColor = null; + private string htmlColor; - public virtual IEnumerable StartChars { get { yield break; } } - public virtual IEnumerable EndChars { get { yield break; } } + public virtual IEnumerable StartChars => Enumerable.Empty(); + public virtual IEnumerable EndChars => Enumerable.Empty(); - public abstract bool IsImplicitMatch(InputLexer lexer); + public abstract bool IsImplicitMatch(CSharpLexer lexer); - public bool IsMatch(InputLexer lexer) + public bool IsMatch(CSharpLexer lexer) { if (IsImplicitMatch(lexer)) { diff --git a/src/Console/Lexer/NumberMatch.cs b/src/Console/Lexer/NumberMatch.cs index 7ff3c4c..68b3d99 100644 --- a/src/Console/Lexer/NumberMatch.cs +++ b/src/Console/Lexer/NumberMatch.cs @@ -2,14 +2,14 @@ namespace UnityExplorer.Console.Lexer { - public sealed class NumberMatch : Matcher + public class NumberMatch : Matcher { public override Color HighlightColor => new Color(0.58f, 0.33f, 0.33f, 1.0f); - public override bool IsImplicitMatch(InputLexer lexer) + public override bool IsImplicitMatch(CSharpLexer lexer) { if (!char.IsWhiteSpace(lexer.Previous) && - !lexer.IsSpecialSymbol(lexer.Previous, SpecialCharacterPosition.End)) + !lexer.IsSpecialSymbol(lexer.Previous, DelimiterType.End)) { return false; } diff --git a/src/Console/Lexer/StringMatch.cs b/src/Console/Lexer/StringMatch.cs index 33309e1..04100df 100644 --- a/src/Console/Lexer/StringMatch.cs +++ b/src/Console/Lexer/StringMatch.cs @@ -3,35 +3,24 @@ using UnityEngine; namespace UnityExplorer.Console.Lexer { - public sealed class StringMatch : Matcher + public class StringMatch : Matcher { public override Color HighlightColor => new Color(0.79f, 0.52f, 0.32f, 1.0f); - public override IEnumerable StartChars { get { yield return '"'; } } - public override IEnumerable EndChars { get { yield return '"'; } } + public override IEnumerable StartChars => new[] { '"' }; + public override IEnumerable EndChars => new[] { '"' }; - public override bool IsImplicitMatch(InputLexer lexer) + public override bool IsImplicitMatch(CSharpLexer lexer) { if (lexer.ReadNext() == '"') { - while (!IsClosingQuoteOrEndFile(lexer, lexer.ReadNext())) - { - ; - } + while (!IsClosingQuoteOrEndFile(lexer, lexer.ReadNext())) { } return true; } return false; } - private bool IsClosingQuoteOrEndFile(InputLexer lexer, char character) - { - if (lexer.EndOfStream == true || - character == '"') - { - return true; - } - return false; - } + private bool IsClosingQuoteOrEndFile(CSharpLexer lexer, char character) => lexer.EndOfStream || character == '"'; } } diff --git a/src/Console/Lexer/SymbolMatch.cs b/src/Console/Lexer/SymbolMatch.cs index 8c0811b..3a9cc72 100644 --- a/src/Console/Lexer/SymbolMatch.cs +++ b/src/Console/Lexer/SymbolMatch.cs @@ -4,54 +4,32 @@ using UnityEngine; namespace UnityExplorer.Console.Lexer { - public sealed class SymbolMatch : Matcher + public class SymbolMatch : Matcher { public override Color HighlightColor => new Color(0.58f, 0.47f, 0.37f, 1.0f); - public string Symbols => @"[ ] ( ) . ? : + - * / % & | ^ ~ = < > ++ -- && || << >> == != <= >= - += -= *= /= %= &= |= ^= <<= >>= -> ?? =>"; + private readonly string[] symbols = new[] + { + "[", "]", "(", ")", ".", "?", ":", "+", "-", "*", "/", "%", "&", "|", "^", "~", "=", "<", ">", + "++", "--", "&&", "||", "<<", ">>", "==", "!=", "<=", ">=", "+=", "-=", "*=", "/=", "%=", "&=", + "|=", "^=", "<<=", ">>=", "->", "??", "=>", + }; private static readonly List shortlist = new List(); private static readonly Stack removeList = new Stack(); - private string[] symbolCache = null; - public override IEnumerable StartChars - { - get - { - BuildSymbolCache(); - foreach (string symbol in symbolCache.Where(x => x.Length > 0)) - { - yield return symbol[0]; - } - } - } + public override IEnumerable StartChars => symbols.Select(s => s[0]); + public override IEnumerable EndChars => symbols.Select(s => s[0]); - public override IEnumerable EndChars - { - get - { - BuildSymbolCache(); - foreach (string symbol in symbolCache.Where(x => x.Length > 0)) - { - yield return symbol[0]; - } - } - } - - public override bool IsImplicitMatch(InputLexer lexer) + public override bool IsImplicitMatch(CSharpLexer lexer) { if (lexer == null) - { return false; - } - - BuildSymbolCache(); if (!char.IsWhiteSpace(lexer.Previous) && !char.IsLetter(lexer.Previous) && !char.IsDigit(lexer.Previous) && - !lexer.IsSpecialSymbol(lexer.Previous, SpecialCharacterPosition.End)) + !lexer.IsSpecialSymbol(lexer.Previous, DelimiterType.End)) { return false; } @@ -61,18 +39,14 @@ namespace UnityExplorer.Console.Lexer int currentIndex = 0; char currentChar = lexer.ReadNext(); - for (int i = symbolCache.Length - 1; i >= 0; i--) + for (int i = symbols.Length - 1; i >= 0; i--) { - if (symbolCache[i][0] == currentChar) - { - shortlist.Add(symbolCache[i]); - } + if (symbols[i][0] == currentChar) + shortlist.Add(symbols[i]); } if (shortlist.Count == 0) - { return false; - } do { @@ -88,7 +62,7 @@ namespace UnityExplorer.Console.Lexer if (char.IsWhiteSpace(currentChar) || char.IsLetter(currentChar) || char.IsDigit(currentChar) || - lexer.IsSpecialSymbol(currentChar, SpecialCharacterPosition.Start)) + lexer.IsSpecialSymbol(currentChar, DelimiterType.Start)) { RemoveLongStrings(currentIndex); lexer.Rollback(1); @@ -128,24 +102,5 @@ namespace UnityExplorer.Console.Lexer shortlist.Remove(removeList.Pop()); } } - - private void BuildSymbolCache() - { - if (symbolCache != null) - { - return; - } - - string[] symSplit = Symbols.Split(' '); - List list = new List(); - foreach (string sym in symSplit) - { - if (!string.IsNullOrEmpty(sym) && sym.Length > 0) - { - list.Add(sym); - } - } - symbolCache = list.ToArray(); - } } } diff --git a/src/Console/Suggestion.cs b/src/Console/Suggestion.cs index eaa19f4..bdb0965 100644 --- a/src/Console/Suggestion.cs +++ b/src/Console/Suggestion.cs @@ -9,25 +9,22 @@ namespace UnityExplorer.Console { public struct Suggestion { - public string Full => Prefix + Addition; + public enum Contexts + { + Namespace, + Keyword, + Other + } + + // ~~~~ Instance ~~~~ public readonly string Prefix; public readonly string Addition; public readonly Contexts Context; - public Color TextColor - { - get - { - switch (Context) - { - case Contexts.Namespace: return Color.grey; - case Contexts.Keyword: return systemBlue; - default: return Color.white; - } - } - } - private static readonly Color systemBlue = new Color(80f / 255f, 150f / 255f, 215f / 255f); + public string Full => Prefix + Addition; + + public Color TextColor => GetTextColor(); public Suggestion(string addition, string prefix, Contexts type) { @@ -36,16 +33,26 @@ namespace UnityExplorer.Console Context = type; } - public enum Contexts + private Color GetTextColor() { - Namespace, - Keyword, - Other + switch (Context) + { + case Contexts.Namespace: return Color.grey; + case Contexts.Keyword: return keywordColor; + default: return Color.white; + } } + // ~~~~ Static ~~~~ + public static HashSet Namespaces => m_namspaces ?? GetNamespaces(); private static HashSet m_namspaces; + public static HashSet Keywords => m_keywords ?? (m_keywords = new HashSet(CSharpLexer.validKeywordMatcher.Keywords)); + private static HashSet m_keywords; + + private static readonly Color keywordColor = new Color(80f / 255f, 150f / 255f, 215f / 255f); + private static HashSet GetNamespaces() { HashSet set = new HashSet( @@ -58,25 +65,5 @@ namespace UnityExplorer.Console IEnumerable GetTypes(Assembly asm) => asm.TryGetTypes(); } - - public static HashSet Keywords => m_keywords ?? GetKeywords(); - private static HashSet m_keywords; - - private static HashSet GetKeywords() - { - if (CSharpLexer.validKeywordMatcher.keywordCache == null) - { - return new HashSet(); - } - - HashSet set = new HashSet(); - - foreach (string keyword in CSharpLexer.validKeywordMatcher.keywordCache) - { - set.Add(keyword); - } - - return m_keywords = set; - } } } diff --git a/src/UI/UIFactory.cs b/src/UI/UIFactory.cs index edaf76c..4c71daf 100644 --- a/src/UI/UIFactory.cs +++ b/src/UI/UIFactory.cs @@ -78,18 +78,15 @@ namespace UnityExplorer.UI if (selectable is Button button) { #if CPP - button.onClick.AddListener(new Action(() => - { - button.OnDeselect(null); - })); + button.onClick.AddListener(new Action(Deselect)); #else button.onClick.AddListener(Deselect); - +#endif void Deselect() { button.OnDeselect(null); } -#endif + } selectable.colors = colors; diff --git a/src/UnityExplorer.csproj b/src/UnityExplorer.csproj index bc29d45..22c3e0d 100644 --- a/src/UnityExplorer.csproj +++ b/src/UnityExplorer.csproj @@ -355,9 +355,8 @@ - - +