mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 12:32:20 +02:00
382 lines
11 KiB
Beef
382 lines
11 KiB
Beef
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Beefy.gfx;
|
|
using Beefy.theme.dark;
|
|
using Beefy.widgets;
|
|
using IDE.Debugger;
|
|
using System.Diagnostics;
|
|
|
|
namespace IDE.ui
|
|
{
|
|
public class EmbeddedEditWidget : ExpressionEditWidget
|
|
{
|
|
public override EditSelection GetCurExprRange()
|
|
{
|
|
int cursorPos = mEditWidgetContent.CursorTextPos;
|
|
|
|
let data = mEditWidgetContent.mData;
|
|
int exprStart = -1;
|
|
|
|
for (int pos < data.mTextLength)
|
|
{
|
|
char8 c = data.mText[pos].mChar;
|
|
if (c == '{')
|
|
{
|
|
if (pos < data.mTextLength - 1)
|
|
{
|
|
char8 nextC = data.mText[pos + 1].mChar;
|
|
if (nextC != '{')
|
|
{
|
|
exprStart = pos + 1;
|
|
}
|
|
}
|
|
}
|
|
else if (c == '}')
|
|
{
|
|
if (exprStart != -1)
|
|
{
|
|
if ((cursorPos >= exprStart) && (cursorPos <= pos))
|
|
{
|
|
return .(exprStart, pos);
|
|
}
|
|
|
|
exprStart = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return .();
|
|
}
|
|
}
|
|
|
|
public class ClearCountButton : Widget
|
|
{
|
|
public override void Draw(Graphics g)
|
|
{
|
|
base.Draw(g);
|
|
|
|
if ((mMouseOver) || (mMouseDown))
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(.CloseOver));
|
|
else
|
|
g.Draw(DarkTheme.sDarkTheme.GetImage(.Close));
|
|
}
|
|
}
|
|
|
|
public class ConditionDialog : IDEDialog
|
|
{
|
|
ExpressionEditWidget mConditionEdit;
|
|
DarkEditWidget mThreadEdit;
|
|
EmbeddedEditWidget mLogEdit;
|
|
DarkCheckBox mBreakAfterLoggingCheckbox;
|
|
DarkEditWidget mHitCountEdit;
|
|
DarkComboBox mHitCountCombo;
|
|
ClearCountButton mClearCountButton;
|
|
List<String> mHitCountKinds = new List<String>() ~ delete _;
|
|
int32 mStartingHitCount;
|
|
int32 mExtraField;
|
|
Breakpoint mBreakpoint;
|
|
|
|
public this()
|
|
{
|
|
mHitCountKinds.Add("Always Break");
|
|
mHitCountKinds.Add("When equals");
|
|
mHitCountKinds.Add("When at least");
|
|
mHitCountKinds.Add("When multiple of");
|
|
mWindowFlags &= ~.Modal;
|
|
}
|
|
|
|
public ~this()
|
|
{
|
|
mBreakpoint?.Deref();
|
|
}
|
|
|
|
public override void CalcSize()
|
|
{
|
|
mWidth = GS!(360);
|
|
mHeight = GS!(270);
|
|
}
|
|
|
|
public bool Finish()
|
|
{
|
|
/*if ((mConditionEdit.mLastError != null) && (mConditionEdit.mLastError != "sideeffects"))
|
|
{
|
|
var err = scope String();
|
|
err.AppendF("Error in Condition:\n{0}", mConditionEdit.mLastError);
|
|
gApp.Fail(err);
|
|
return false;
|
|
}
|
|
|
|
if (mLogEdit.mLastError != null)
|
|
{
|
|
var err = scope String();
|
|
err.AppendF("Error in Log String:\n{0}", mConditionEdit.mLastError);
|
|
gApp.Fail(err);
|
|
return false;
|
|
}*/
|
|
|
|
var sourceEditWidgetContent = (SourceEditWidgetContent)mConditionEdit.Content;
|
|
if (sourceEditWidgetContent.mAutoComplete != null)
|
|
sourceEditWidgetContent.KeyChar('\t');
|
|
|
|
String conditionStr = scope String();
|
|
mConditionEdit.GetText(conditionStr);
|
|
conditionStr.Trim();
|
|
|
|
int threadId = -1;
|
|
String threadStr = scope String();
|
|
mThreadEdit.GetText(threadStr);
|
|
threadStr.Trim();
|
|
if (!threadStr.IsWhiteSpace)
|
|
{
|
|
if (threadStr == ".")
|
|
{
|
|
threadId = gApp.mDebugger.GetActiveThread();
|
|
}
|
|
else
|
|
{
|
|
switch (Int.Parse(threadStr))
|
|
{
|
|
case .Ok(out threadId):
|
|
case .Err:
|
|
gApp.Fail("Invalid value for Thread Id");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
String loggingStr = scope String();
|
|
mLogEdit.GetText(loggingStr);
|
|
loggingStr.Trim();
|
|
|
|
String hitCountTargetStr = scope String();
|
|
mHitCountEdit.GetText(hitCountTargetStr);
|
|
hitCountTargetStr.Trim();
|
|
int32 targetHitCount = 0;
|
|
|
|
Breakpoint.HitCountBreakKind hitCountBreakKind = (.)mHitCountKinds.IndexOf(scope String(mHitCountCombo.Label));
|
|
|
|
if (!hitCountTargetStr.IsWhiteSpace)
|
|
{
|
|
if (hitCountTargetStr == ".")
|
|
{
|
|
targetHitCount = mStartingHitCount;
|
|
}
|
|
else
|
|
{
|
|
switch (Int32.Parse(hitCountTargetStr))
|
|
{
|
|
case .Ok(out targetHitCount):
|
|
case .Err:
|
|
gApp.Fail("Invalid value for Target Hit Count");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool breakOnLogging = mBreakAfterLoggingCheckbox.Checked;
|
|
gApp.mBreakpointPanel.ConfigureBreakpoint(mBreakpoint, conditionStr, threadId, loggingStr, breakOnLogging, targetHitCount, hitCountBreakKind);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SetupExprEvaluator(ExpressionEditWidget exprEditWidget)
|
|
{
|
|
if (mBreakpoint.mAddrType != null)
|
|
{
|
|
var exprPre = new String();
|
|
var exprPost = new String();
|
|
exprEditWidget.mExprPre = exprPre;
|
|
exprEditWidget.mExprPost = exprPost;
|
|
|
|
var enumerator = mBreakpoint.mAddrType.Split('\t');
|
|
int langVal = int.Parse(enumerator.GetNext().Get()).Get();
|
|
StringView addrVal = enumerator.GetNext().Get();
|
|
if (langVal == (.)DebugManager.Language.C)
|
|
exprPre.Append("@C:");
|
|
else
|
|
exprPre.Append("@Beef:");
|
|
exprPost.AppendF(",_=*({0}*)0x", addrVal);
|
|
mBreakpoint.mMemoryAddress.ToString(exprPost, "X", null);
|
|
exprPost.Append("L");
|
|
}
|
|
}
|
|
|
|
public void Init(Breakpoint breakpoint)
|
|
{
|
|
bool ignoreErrors = !gApp.mDebugger.IsPaused();
|
|
|
|
mBreakpoint = breakpoint;
|
|
mBreakpoint.AddRef();
|
|
|
|
var title = scope String();
|
|
title.Append("Configure Breakpoint - ");
|
|
breakpoint.ToString_Location(title);
|
|
Title = title;
|
|
|
|
mDefaultButton = AddButton("OK", new (evt) => { if (!Finish()) evt.mCloseDialog = false; });
|
|
mEscButton = AddButton("Cancel", new (evt) => Close());
|
|
|
|
mStartingHitCount = (.)breakpoint.GetHitCount();
|
|
|
|
mConditionEdit = new ExpressionEditWidget();
|
|
SetupExprEvaluator(mConditionEdit);
|
|
mConditionEdit.mIgnoreErrors = ignoreErrors;
|
|
// Just try at first address
|
|
void* nextAddr = null;
|
|
mConditionEdit.mEvalAtAddress = breakpoint.GetAddress(ref nextAddr);
|
|
if (breakpoint.mCondition != null)
|
|
{
|
|
mConditionEdit.SetText(breakpoint.mCondition);
|
|
mConditionEdit.Content.SelectAll();
|
|
}
|
|
AddEdit(mConditionEdit);
|
|
|
|
mThreadEdit = new DarkEditWidget();
|
|
((DarkEditWidgetContent)mThreadEdit.mEditWidgetContent).mScrollToStartOnLostFocus = true;
|
|
if (breakpoint.mThreadId != -1)
|
|
{
|
|
var str = scope String();
|
|
breakpoint.mThreadId.ToString(str);
|
|
mThreadEdit.SetText(str);
|
|
mThreadEdit.Content.SelectAll();
|
|
}
|
|
AddEdit(mThreadEdit);
|
|
|
|
mHitCountCombo = new DarkComboBox();
|
|
mHitCountCombo.Label = mHitCountKinds[(int)breakpoint.mHitCountBreakKind];
|
|
mHitCountCombo.mPopulateMenuAction.Add(new (dlg) =>
|
|
{
|
|
for (let str in mHitCountKinds)
|
|
{
|
|
var item = dlg.AddItem(str);
|
|
item.mOnMenuItemSelected.Add(new (item) =>
|
|
{
|
|
// If there is no number etered yet, default to
|
|
var hitCountStr = scope String();
|
|
mHitCountEdit.GetText(hitCountStr);
|
|
if ((hitCountStr.IsWhiteSpace) && (item.mLabel != mHitCountKinds[0]))
|
|
{
|
|
hitCountStr.Clear();
|
|
breakpoint.GetHitCount().ToString(hitCountStr);
|
|
mHitCountEdit.SetText(hitCountStr);
|
|
}
|
|
|
|
mHitCountCombo.Label = item.mLabel;
|
|
MarkDirty();
|
|
});
|
|
}
|
|
});
|
|
AddDialogComponent(mHitCountCombo);
|
|
|
|
mHitCountEdit = new DarkEditWidget();
|
|
((DarkEditWidgetContent)mHitCountEdit.mEditWidgetContent).mScrollToStartOnLostFocus = true;
|
|
if (breakpoint.mHitCountTarget != 0)
|
|
{
|
|
var str = scope String();
|
|
breakpoint.mHitCountTarget.ToString(str);
|
|
mHitCountEdit.SetText(str);
|
|
mHitCountEdit.Content.SelectAll();
|
|
}
|
|
AddEdit(mHitCountEdit);
|
|
|
|
mClearCountButton = new ClearCountButton();
|
|
mClearCountButton.mOnMouseDown.Add(new (widget) =>
|
|
{
|
|
gApp.mBreakpointPanel.ClearHitCounts();
|
|
mStartingHitCount = 0;
|
|
});
|
|
AddWidget(mClearCountButton);
|
|
|
|
mLogEdit = new EmbeddedEditWidget();
|
|
mLogEdit.mIgnoreErrors = ignoreErrors;
|
|
SetupExprEvaluator(mLogEdit);
|
|
AddEdit(mLogEdit);
|
|
if (breakpoint.mLogging != null)
|
|
{
|
|
mLogEdit.SetText(breakpoint.mLogging);
|
|
mLogEdit.Content.SelectAll();
|
|
}
|
|
|
|
mBreakAfterLoggingCheckbox = new DarkCheckBox();
|
|
mBreakAfterLoggingCheckbox.Label = "Break after logging";
|
|
mBreakAfterLoggingCheckbox.Checked = breakpoint.mBreakAfterLogging;
|
|
AddDialogComponent(mBreakAfterLoggingCheckbox);
|
|
}
|
|
|
|
public override void PopupWindow(WidgetWindow parentWindow, float offsetX = 0, float offsetY = 0)
|
|
{
|
|
base.PopupWindow(parentWindow, offsetX, offsetY);
|
|
mConditionEdit.SetFocus();
|
|
}
|
|
|
|
public override void ResizeComponents()
|
|
{
|
|
base.ResizeComponents();
|
|
|
|
float editWidth = GS!(100);
|
|
|
|
float curY = mHeight - GS!(20) - mButtonBottomMargin;
|
|
mLogEdit.Resize(GS!(16), curY - GS!(36), mWidth - GS!(16) * 2, GS!(28));
|
|
mBreakAfterLoggingCheckbox.Resize(mWidth - mBreakAfterLoggingCheckbox.CalcWidth() - GS!(16), curY - GS!(36) - GS!(20), mBreakAfterLoggingCheckbox.CalcWidth() + GS!(4), GS!(28));
|
|
|
|
curY -= GS!(56);
|
|
mHitCountEdit.Resize(mWidth - editWidth - GS!(16), curY - GS!(36), editWidth, GS!(28));
|
|
mHitCountCombo.Resize(GS!(16), curY - GS!(36) + GS!(2), mWidth - GS!(16)*2 - editWidth - GS!(4), GS!(28));
|
|
mClearCountButton.Resize(mWidth - GS!(28), curY - GS!(36) - GS!(19), GS!(20), GS!(20));
|
|
|
|
curY -= GS!(56);
|
|
mThreadEdit.Resize(GS!(16), curY - GS!(36), mWidth - GS!(16) * 2, GS!(28));
|
|
|
|
curY -= GS!(56);
|
|
mConditionEdit.Resize(GS!(16), curY - GS!(36), mWidth - GS!(16) * 2, GS!(28));
|
|
|
|
delete mClearCountButton.mMouseInsets;
|
|
mClearCountButton.mMouseInsets = new .(GS!(4), GS!(4), GS!(4), GS!(4));
|
|
}
|
|
|
|
public override bool HandleTab(int dir)
|
|
{
|
|
var sourceEditWidgetContent = (SourceEditWidgetContent)mConditionEdit.Content;
|
|
if ((sourceEditWidgetContent.mAutoComplete != null) && (sourceEditWidgetContent.mAutoComplete.IsShowing()))
|
|
{
|
|
//sourceEditWidgetContent.KeyChar('\t');
|
|
return false;
|
|
}
|
|
|
|
return base.HandleTab(dir);
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
int hitCount = mBreakpoint.GetHitCount();
|
|
if (hitCount != mStartingHitCount)
|
|
{
|
|
mStartingHitCount = (.)hitCount;
|
|
MarkDirty();
|
|
}
|
|
|
|
if (mBreakpoint.mIsDead)
|
|
{
|
|
// This breakpoint was deleted
|
|
Close();
|
|
}
|
|
}
|
|
|
|
public override void Draw(Graphics g)
|
|
{
|
|
base.Draw(g);
|
|
|
|
g.DrawString("Breakpoint Condition", mConditionEdit.mX, mConditionEdit.mY - GS!(20));
|
|
g.DrawString("Thread Id", mThreadEdit.mX, mThreadEdit.mY - GS!(20));
|
|
g.DrawString("Log String", mLogEdit.mX, mLogEdit.mY - GS!(20));
|
|
g.DrawString("Break on Hit Count", mHitCountCombo.mX, mHitCountEdit.mY - GS!(19));
|
|
|
|
var str = scope String();
|
|
str.AppendF("Current: {0}", mStartingHitCount);
|
|
g.DrawString(str, mWidth - GS!(16) - GS!(8), mHitCountEdit.mY - GS!(19), .Right);
|
|
}
|
|
}
|
|
}
|