Debugger: Improved syntax highlighting
This commit is contained in:
parent
408dacb2e9
commit
bb02c4352a
6 changed files with 116 additions and 64 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
69
UI/Debugger/Code/CodeHighlighting.cs
Normal file
69
UI/Debugger/Code/CodeHighlighting.cs
Normal 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 } };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" />
|
||||
|
|
Loading…
Add table
Reference in a new issue