diff --git a/UI/Debugger/Code/BaseStyleProvider.cs b/UI/Debugger/Code/BaseStyleProvider.cs index 2efacde..f2f7f5c 100644 --- a/UI/Debugger/Code/BaseStyleProvider.cs +++ b/UI/Debugger/Code/BaseStyleProvider.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace Mesen.GUI.Debugger.Code { - public abstract class BaseStyleProvider : ctrlTextbox.ILineStyleProvider + public abstract class BaseStyleProvider : ILineStyleProvider { public int? ActiveAddress { get; set; } @@ -45,5 +45,10 @@ namespace Mesen.GUI.Debugger.Code props.OutlineColor = outlineColor; props.Symbol = symbol; } + + public List GetCodeColors(CodeLineData lineData, bool highlightCode, string addressFormat, Color? textColor, bool showMemoryValues) + { + return CodeHighlighting.GetCpuHighlights(lineData, highlightCode, addressFormat, textColor, showMemoryValues); + } } } diff --git a/UI/Debugger/Code/CodeHighlighting.cs b/UI/Debugger/Code/CodeHighlighting.cs new file mode 100644 index 0000000..7badbc7 --- /dev/null +++ b/UI/Debugger/Code/CodeHighlighting.cs @@ -0,0 +1,69 @@ +using Mesen.GUI.Config; +using Mesen.GUI.Debugger.Controls; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Mesen.GUI.Debugger.Code +{ + class CodeHighlighting + { + private static Regex _space = new Regex("^[ \t]+", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private static Regex _opCode = new Regex("^[a-z0-9]{2,5}", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private static Regex _syntax = new Regex("^[]([)!+,.]{1}", RegexOptions.Compiled); + private static Regex _operand = new Regex("^(([$][0-9a-f]*([.]\\d){0,1})|(#[@$:_0-9a-z]*)|([@_a-z]([@_a-z0-9])*))", RegexOptions.IgnoreCase | RegexOptions.Compiled); + + public static List GetCpuHighlights(CodeLineData lineData, bool highlightCode, string addressFormat, Color? textColor, bool showMemoryValues) + { + DebuggerInfo cfg = ConfigManager.Config.Debug.Debugger; + string codeString = lineData.Text; + Color defaultColor = Color.FromArgb(60, 60, 60); + + if(codeString.Length > 0 && highlightCode && !lineData.Flags.HasFlag(LineFlags.Label)) { + List colors = new List(); + bool foundOpCode = false; + while(codeString.Length > 0) { + Match m; + if(foundOpCode && (m = _operand.Match(codeString)).Success) { + string operand = m.Value; + Color operandColor = operand.Length > 0 ? (operand[0] == '#' ? (Color)cfg.CodeImmediateColor : (operand[0] == '$' ? (Color)cfg.CodeAddressColor : (Color)cfg.CodeLabelDefinitionColor)) : Color.Black; + colors.Add(new CodeColor() { Text = m.Value, Color = textColor.HasValue ? textColor.Value : operandColor }); + } else if(!foundOpCode && (m = _opCode.Match(codeString)).Success) { + foundOpCode = true; + colors.Add(new CodeColor() { Text = m.Value, Color = textColor.HasValue ? textColor.Value : (Color)cfg.CodeOpcodeColor }); + } else if((m = _syntax.Match(codeString)).Success) { + colors.Add(new CodeColor() { Text = m.Value, Color = textColor.HasValue ? textColor.Value : defaultColor }); + } else if((m = _space.Match(codeString)).Success) { + colors.Add(new CodeColor() { Text = m.Value, Color = textColor.HasValue ? textColor.Value : defaultColor }); + } + + if(m.Success) { + codeString = codeString.Substring(m.Value.Length); + } else { + break; + } + } + + //Display the rest of the line (used by trace logger) + colors.Add(new CodeColor() { Text = codeString, Color = defaultColor }); + + if(lineData.EffectiveAddress >= 0) { + colors.Add(new CodeColor() { Text = " " + lineData.GetEffectiveAddressString(addressFormat), Color = cfg.CodeEffectiveAddressColor }); + } + + if(showMemoryValues && lineData.ValueSize > 0) { + colors.Add(new CodeColor() { Text = lineData.GetValueString(), Color = defaultColor }); + } + + return colors; + } else { + Color color = codeString.EndsWith(":") ? (Color)cfg.CodeLabelDefinitionColor : (textColor ?? defaultColor); + return new List() { new CodeColor() { Text = codeString, Color = color } }; + } + } + } +} diff --git a/UI/Debugger/Controls/ctrlScrollableTextbox.cs b/UI/Debugger/Controls/ctrlScrollableTextbox.cs index b0e8b87..d95278a 100644 --- a/UI/Debugger/Controls/ctrlScrollableTextbox.cs +++ b/UI/Debugger/Controls/ctrlScrollableTextbox.cs @@ -179,7 +179,7 @@ namespace Mesen.GUI.Debugger.Controls this.hScrollBar.Maximum = newMax; } - public ctrlTextbox.ILineStyleProvider StyleProvider { set { this.ctrlTextbox.StyleProvider = value; } } + public ILineStyleProvider StyleProvider { set { this.ctrlTextbox.StyleProvider = value; } } public ICodeDataProvider DataProvider { diff --git a/UI/Debugger/Controls/ctrlTextbox.cs b/UI/Debugger/Controls/ctrlTextbox.cs index 6824542..79f0ac7 100644 --- a/UI/Debugger/Controls/ctrlTextbox.cs +++ b/UI/Debugger/Controls/ctrlTextbox.cs @@ -16,7 +16,6 @@ namespace Mesen.GUI.Debugger.Controls { public partial class ctrlTextbox : Control { - private Regex _codeRegex = new Regex("^(\\s*)([a-z]{3})([*]{0,1})($|[ ]){1}([(\\[]{0,1})(([$][0-9a-f]*)|(#[@$:_0-9a-z]*)|([@_a-z]([@_a-z0-9])*){0,1}(\\+(\\d+)){0,1}){0,1}([)\\]]{0,1})(,X|,Y){0,1}([)\\]]{0,1})(.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled); public event EventHandler ScrollPositionChanged; public event EventHandler SelectedLineChanged; private bool _disableScrollPositionChangedEvent; @@ -288,12 +287,6 @@ namespace Mesen.GUI.Debugger.Controls } } - public interface ILineStyleProvider - { - LineProperties GetLineStyle(CodeLineData lineData, int lineIndex); - string GetLineComment(int lineIndex); - } - private ILineStyleProvider _styleProvider; public ILineStyleProvider StyleProvider { @@ -911,7 +904,7 @@ namespace Mesen.GUI.Debugger.Controls } } - this.DrawLineText(g, currentLine, marginLeft, positionY, lineData, codeStringLength, textColor, lineHeight); + this.DrawLineText(g, currentLine, marginLeft, positionY, lineData, textColor, lineHeight); } private void DrawLineNumber(Graphics g, CodeLineData lineData, int marginLeft, int positionY, Color addressColor) @@ -955,13 +948,12 @@ namespace Mesen.GUI.Debugger.Controls } } - private void DrawLineText(Graphics g, int currentLine, int marginLeft, int positionY, CodeLineData lineData, float codeStringLength, Color? textColor, int lineHeight) + private void DrawLineText(Graphics g, int currentLine, int marginLeft, int positionY, CodeLineData lineData, Color? textColor, int lineHeight) { string codeString = lineData.Text; string commentString = lineData.Comment; + int characterCount = 0; - DebuggerInfo cfg = ConfigManager.Config.Debug.Debugger; - if(lineData.Flags.HasFlag(LineFlags.BlockEnd) || lineData.Flags.HasFlag(LineFlags.BlockStart)) { //Draw block start/end g.TranslateTransform(HorizontalScrollPosition * HorizontalScrollFactor, 0); @@ -981,6 +973,7 @@ namespace Mesen.GUI.Debugger.Controls } g.TranslateTransform(-HorizontalScrollPosition * HorizontalScrollFactor, 0); } else { + List colors = null; if(StyleProvider != null) { string symbolComment = StyleProvider.GetLineComment(currentLine); if(symbolComment != null) { @@ -993,69 +986,33 @@ namespace Mesen.GUI.Debugger.Controls _lastSymbolComment = symbolComment; } } + + colors = StyleProvider.GetCodeColors(lineData, CodeHighlightingEnabled, _addressFormat, textColor, _showMemoryValues); } - //Draw line content - int characterCount = 0; - Color defaultColor = Color.FromArgb(60, 60, 60); - if(codeString.Length > 0) { - Match match = CodeHighlightingEnabled ? _codeRegex.Match(codeString) : null; - if(match != null && match.Success && !lineData.Flags.HasFlag(LineFlags.Label)) { - string padding = match.Groups[1].Value; - string opcode = match.Groups[2].Value; - string invalidStar = match.Groups[3].Value; - string paren1 = match.Groups[5].Value; - string operand = match.Groups[6].Value; - string arrayPosition = match.Groups[12].Value; - string paren2 = match.Groups[13].Value; - string indirect = match.Groups[14].Value; - string paren3 = match.Groups[15].Value; - string rest = match.Groups[16].Value; - Color operandColor = operand.Length > 0 ? (operand[0] == '#' ? (Color)cfg.CodeImmediateColor : (operand[0] == '$' ? (Color)cfg.CodeAddressColor : (Color)cfg.CodeLabelDefinitionColor)) : Color.Black; - List colors = new List() { defaultColor, cfg.CodeOpcodeColor, defaultColor, defaultColor, defaultColor, operandColor, defaultColor, defaultColor, defaultColor }; - int codePartCount = colors.Count; - - List parts = new List() { padding, opcode, invalidStar, " ", paren1, operand, paren2, indirect, paren3 }; - - //Display the rest of the line (used by trace logger) - colors.Add(defaultColor); - parts.Add(rest); - - if(lineData.EffectiveAddress >= 0) { - colors.Add(cfg.CodeEffectiveAddressColor); - parts.Add(" " + lineData.GetEffectiveAddressString(_addressFormat)); + if(colors != null) { + float xOffset = 0; + foreach(CodeColor codeColor in colors) { + using(Brush b = new SolidBrush(codeColor.Color)) { + g.DrawString(codeColor.Text, this.Font, b, marginLeft + xOffset, positionY, StringFormat.GenericTypographic); + xOffset += g.MeasureString("".PadLeft(codeColor.Text.Length, 'w'), this.Font, Point.Empty, StringFormat.GenericTypographic).Width; + characterCount += codeColor.Text.Length; } - - if(this.ShowMemoryValues && lineData.ValueSize > 0) { - colors.Add(defaultColor); - parts.Add(lineData.GetValueString()); - } - - float xOffset = 0; - for(int i = 0; i < parts.Count; i++) { - using(Brush b = new SolidBrush(textColor.HasValue && (i <= codePartCount) ? textColor.Value : colors[i])) { - g.DrawString(parts[i], this.Font, b, marginLeft + xOffset, positionY, StringFormat.GenericTypographic); - xOffset += g.MeasureString("".PadLeft(parts[i].Length, 'w'), this.Font, Point.Empty, StringFormat.GenericTypographic).Width; - characterCount += parts[i].Length; - } - } - codeStringLength = xOffset; - } else { - using(Brush fgBrush = new SolidBrush(codeString.EndsWith(":") ? (Color)cfg.CodeLabelDefinitionColor : (textColor ?? defaultColor))) { - g.DrawString(codeString, this.Font, fgBrush, marginLeft, positionY, StringFormat.GenericTypographic); - } - characterCount = codeString.Trim().Length; } + } else { + g.DrawString(codeString, this.Font, Brushes.Black, marginLeft, positionY, StringFormat.GenericTypographic); + characterCount = codeString.Trim().Length; } if(!string.IsNullOrWhiteSpace(commentString)) { + DebuggerInfo cfg = ConfigManager.Config.Debug.Debugger; using(Brush commentBrush = new SolidBrush(cfg.CodeCommentColor)) { int padding = Math.Max(CommentSpacingCharCount, characterCount + 1); if(characterCount == 0) { //Draw comment left-aligned, next to the margin when there is no code on the line padding = 0; } - g.DrawString(commentString.PadLeft(padding+commentString.Length), this.Font, commentBrush, marginLeft, positionY, StringFormat.GenericTypographic); + g.DrawString(commentString.PadLeft(padding + commentString.Length), this.Font, commentBrush, marginLeft, positionY, StringFormat.GenericTypographic); } } @@ -1375,4 +1332,18 @@ namespace Mesen.GUI.Debugger.Controls int GetLineAddress(int lineIndex); int GetLineIndex(UInt32 address); } + + public interface ILineStyleProvider + { + LineProperties GetLineStyle(CodeLineData lineData, int lineIndex); + string GetLineComment(int lineIndex); + + List GetCodeColors(CodeLineData lineData, bool highlightCode, string addressFormat, Color? textColor, bool showMemoryValues); + } + + public class CodeColor + { + public string Text; + public Color Color; + } } diff --git a/UI/Debugger/frmTraceLogger.cs b/UI/Debugger/frmTraceLogger.cs index f56b6d2..6827601 100644 --- a/UI/Debugger/frmTraceLogger.cs +++ b/UI/Debugger/frmTraceLogger.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using System.Windows.Forms; using Mesen.GUI.Config; using Mesen.GUI.Controls; +using Mesen.GUI.Debugger.Code; using Mesen.GUI.Debugger.Controls; using Mesen.GUI.Forms; @@ -569,7 +570,7 @@ namespace Mesen.GUI.Debugger } } - public class TraceLoggerStyleProvider : ctrlTextbox.ILineStyleProvider + public class TraceLoggerStyleProvider : ILineStyleProvider { private Color _spcColor = Color.FromArgb(30, 145, 30); private Color _spcBgColor = Color.FromArgb(230, 245, 230); @@ -583,6 +584,11 @@ namespace Mesen.GUI.Debugger _flags = lineFlags; } + public List GetCodeColors(CodeLineData lineData, bool highlightCode, string addressFormat, Color? textColor, bool showMemoryValues) + { + return CodeHighlighting.GetCpuHighlights(lineData, highlightCode, addressFormat, textColor, showMemoryValues); + } + public string GetLineComment(int lineIndex) { return null; diff --git a/UI/UI.csproj b/UI/UI.csproj index 86ab642..2a8f10d 100644 --- a/UI/UI.csproj +++ b/UI/UI.csproj @@ -258,6 +258,7 @@ +