Debugger: Improved syntax highlighting

This commit is contained in:
Sour 2020-02-07 21:48:52 -05:00
parent 408dacb2e9
commit bb02c4352a
6 changed files with 116 additions and 64 deletions

View file

@ -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<CodeColor> GetCodeColors(CodeLineData lineData, bool highlightCode, string addressFormat, Color? textColor, bool showMemoryValues)
{
return CodeHighlighting.GetCpuHighlights(lineData, highlightCode, addressFormat, textColor, showMemoryValues);
}
}
}

View file

@ -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<CodeColor> 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<CodeColor> colors = new List<CodeColor>();
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<CodeColor>() { new CodeColor() { Text = codeString, Color = color } };
}
}
}
}

View file

@ -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
{

View file

@ -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<CodeColor> 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<Color> colors = new List<Color>() { defaultColor, cfg.CodeOpcodeColor, defaultColor, defaultColor, defaultColor, operandColor, defaultColor, defaultColor, defaultColor };
int codePartCount = colors.Count;
List<string> parts = new List<string>() { 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<CodeColor> GetCodeColors(CodeLineData lineData, bool highlightCode, string addressFormat, Color? textColor, bool showMemoryValues);
}
public class CodeColor
{
public string Text;
public Color Color;
}
}

View file

@ -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<CodeColor> 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;

View file

@ -258,6 +258,7 @@
</Compile>
<Compile Include="Debugger\Breakpoints\InteropBreakpoint.cs" />
<Compile Include="Debugger\Code\BaseStyleProvider.cs" />
<Compile Include="Debugger\Code\CodeHighlighting.cs" />
<Compile Include="Debugger\Code\Sa1LineStyleProvider.cs" />
<Compile Include="Debugger\Code\SymbolCodeDataProvider.cs" />
<Compile Include="Debugger\Code\Sa1DisassemblyManager.cs" />