1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-09 03:52:19 +02:00

Collapsible regions (aka outlining aka code folding)

This commit is contained in:
Brian Fiete 2022-02-28 11:27:12 -08:00
parent 3dd4212ccd
commit 90735e3bf8
21 changed files with 2518 additions and 277 deletions

View file

@ -346,6 +346,7 @@ namespace Beefy
return list;
}*/
[DisableChecks]
public static int64 DecodeInt64(ref uint8* ptr)
{
int64 value = 0;
@ -364,6 +365,7 @@ namespace Beefy
return value;
}
[DisableChecks]
public static int32 DecodeInt(uint8[] buf, ref int idx)
{
int32 value = 0;
@ -383,6 +385,7 @@ namespace Beefy
return value;
}
[DisableChecks]
public static void EncodeInt(uint8[] buf, ref int idx, int value)
{
int curValue = value;

View file

@ -5,11 +5,49 @@ using System.Text;
using Beefy.widgets;
using Beefy.gfx;
using Beefy.utils;
using Beefy.geom;
namespace Beefy.theme.dark
{
public class DarkEditWidgetContent : EditWidgetContent
{
public class Embed
{
public enum Kind
{
LineStart,
HideLine,
LineEnd,
}
public Kind mKind;
public ~this()
{
}
public virtual void Draw(Graphics g, Rect rect, bool hideLine)
{
}
public virtual void MouseDown(float x, float y, int btn, int btnCount)
{
}
public virtual float GetWidth(bool hideLine)
{
return GS!(24);
}
}
public class Data : EditWidgetContent.Data
{
}
public Font mFont;
public uint32[] mTextColors = sDefaultColors;
public uint32 mHiliteColor = 0xFF2f5c88;
@ -23,6 +61,7 @@ namespace Beefy.theme.dark
public uint32 mViewWhiteSpaceColor;
public bool mScrollToStartOnLostFocus;
public bool mHiliteCurrentLine;
public Dictionary<int, Embed> mEmbeds = new .() ~ DeleteDictionaryAndValues!(_);
protected static uint32[] sDefaultColors = new uint32[] ( Color.White ) ~ delete _;
@ -39,6 +78,48 @@ namespace Beefy.theme.dark
mFont = DarkTheme.sDarkTheme?.mSmallFont;
}
protected override EditWidgetContent.Data CreateEditData()
{
return new Data();
}
public virtual void CheckLineCoords()
{
if (mLineCoordTextVersionId == mData.mCurTextVersionId)
return;
mLineCoordTextVersionId = mData.mCurTextVersionId;
if (mLineCoords == null)
mLineCoords = new .();
if (mLineCoordJumpTable == null)
mLineCoordJumpTable = new .();
mLineCoords.Clear();
mLineCoords.GrowUnitialized(mData.mLineStarts.Count);
mLineCoordJumpTable.Clear();
float fontHeight = mFont.GetLineSpacing();
int prevJumpIdx = -1;
float jumpCoordSpacing = GetJumpCoordSpacing();
double curY = 0;
for (int line < mData.mLineStarts.Count)
{
float lineHeight = fontHeight;
mLineCoords[line] = (float)curY;
int jumpIdx = (.)(curY / jumpCoordSpacing);
while (prevJumpIdx < jumpIdx)
{
mLineCoordJumpTable.Add(((int32)line, (int32)line + 1));
prevJumpIdx++;
}
mLineCoordJumpTable[jumpIdx].max = (.)line + 1;
curY += lineHeight;
}
}
public override void GetTextData()
{
// Generate text flags if we need to...
@ -97,6 +178,54 @@ namespace Beefy.theme.dark
}
base.GetTextData();
CheckLineCoords();
}
public int32 mLineCoordTextVersionId = -1;
public List<float> mLineCoords ~ delete _;
public List<(int32 min, int32 max)> mLineCoordJumpTable ~ delete _;
public bool IsLineCollapsed(int line)
{
if (mLineCoords == null)
return false;
if ((line >= 0) && (line < mLineCoords.Count - 1))
return (mLineCoords[line + 1] - mLineCoords[line]) < 0.1f;
return false;
}
public float GetLineHeight(int line, float defaultVal)
{
if ((line >= 0) && (line < mLineCoords.Count - 1))
return mLineCoords[line + 1] - mLineCoords[line];
return defaultVal;
}
public float GetLineY(int line, float defaultVal)
{
if ((line >= 0) && (line < mLineCoords.Count))
return mLineCoords[line];
return defaultVal;
}
public int FindUncollapsedLine(int line)
{
var line;
while ((line > 0) && (IsLineCollapsed(line)))
line--;
return line;
}
public bool IsInCollapseGroup(int anchorLine, int checkLine)
{
if (checkLine < anchorLine)
return false;
if (checkLine == anchorLine)
return true;
if (checkLine == anchorLine + 1)
return IsLineCollapsed(checkLine);
return mLineCoords[anchorLine + 1] == mLineCoords[checkLine + 1];
}
protected override void AdjustCursorsAfterExternalEdit(int index, int ofs)
@ -322,6 +451,8 @@ namespace Beefy.theme.dark
Utils.RoundScale(ref mTabSize, newScale / oldScale);
SetFont(mFont, mCharWidth != -1, mAllowVirtualCursor);
mContentChanged = true; // Defer calling of RecalcSize
GetTextData();
LineStartsChanged();
}
public virtual float DrawText(Graphics g, String str, float x, float y, uint16 typeIdAndFlags)
@ -335,15 +466,52 @@ namespace Beefy.theme.dark
return mEditWidget.mHasFocus ? mHiliteColor : mUnfocusedHiliteColor;
}
protected Rect GetEmbedRect(int lineIdx, DarkEditWidgetContent.Embed embed)
{
GetLinePosition(lineIdx, var lineStart, var lineEnd);
bool hideLine = false;
if ((embed.mKind == .HideLine) &&
((!mEditWidget.mHasFocus) || (!IsInCollapseGroup(lineIdx, CursorLine))))
hideLine = true;
int wsEnd = lineEnd;
if ((hideLine) || (embed.mKind == .LineStart))
{
for (int i in lineStart..<lineEnd)
{
var checkEnd = ref mData.mText[i];
if (!checkEnd.mChar.IsWhiteSpace)
{
wsEnd = i;
break;
}
}
}
String str = scope .(256);
ExtractString(lineStart, wsEnd - lineStart, str);
float selStartX = GetTabbedWidth(str, 0);
if ((embed.mKind == .LineEnd) ||
((embed.mKind == .HideLine) && (!hideLine)))
selStartX += GS!(4);
Rect rect = .(selStartX, mLineCoords[lineIdx] - GS!(2), embed.GetWidth(hideLine), mFont.GetLineSpacing() + GS!(4));
if (rect.mY < 0)
rect.mY = 0;
return rect;
}
public override void Draw(Graphics g)
{
base.Draw(g);
#unwarn
int lineCount = GetLineCount();
float lineSpacing = GetLineHeight(0);
g.SetFont(mFont);
float lineSpacing = mFont.GetLineSpacing();
float offsetY = mTextInsets.mTop;
if (mHeight < lineSpacing)
@ -377,6 +545,49 @@ namespace Beefy.theme.dark
GetLineCharAtCoord(0, -mY + mEditWidget.mScrollContentContainer.mHeight, out lastLine, out lastCharIdx, out lastOverflowX);
bool drewCursor = false;
void DrawCursor(float x, float y)
{
if (mHiliteCurrentLine && selStartIdx == selEndIdx)
{
float thickness = 2 * (lineSpacing / 18);
// This isn't quite the right value, but I'm not sure how to get this
// to properly highlight the whole line without getting cut off - this works well for now.
float totalLineWidth = mEditWidget.mScrollContentContainer.mWidth - thickness;
float hiliteX = (int)mEditWidget.mHorzPos.v; // If we don't round to int we get jitter while scrolling.
using (g.PushColor(DarkTheme.COLOR_CURRENT_LINE_HILITE))
g.OutlineRect(hiliteX, y, totalLineWidth, lineSpacing + thickness, thickness);
}
float brightness = (float)Math.Cos(Math.Max(0.0f, mCursorBlinkTicks - 20) / 9.0f);
brightness = Math.Clamp(brightness * 2.0f + 1.6f, 0, 1);
if (mEditWidget.mVertPos.IsMoving)
brightness = 0; // When we animate a pgup or pgdn, it's weird seeing the cursor scrolling around
Color cursorColor = mTextColors[0];
if (mOverTypeMode)
{
if (mCharWidth <= 2)
{
using (g.PushColor(Color.Mult(cursorColor, Color.Get(brightness * 0.75f))))
g.FillRect(x, y, GS!(2), lineSpacing);
}
else
{
using (g.PushColor(Color.Mult(cursorColor, Color.Get(brightness * 0.30f))))
g.FillRect(x, y, mCharWidth, lineSpacing);
}
}
else
{
using (g.PushColor(Color.Mult(cursorColor, Color.Get(brightness))))
g.FillRect(x, y, Math.Max(1.0f, GS!(1)), lineSpacing);
}
drewCursor = true;
}
String sectionText = scope String(256);
for (int lineIdx = firstLine; lineIdx <= lastLine; lineIdx++)
{
@ -387,7 +598,26 @@ namespace Beefy.theme.dark
int lineDrawStart = lineStart;
float curX = 0;
float curY = lineIdx * lineSpacing;
float curY = mLineCoords[lineIdx];
float height = mLineCoords[lineIdx + 1] - curY;
if (height <= 1.0f)
continue;
DarkEditWidgetContent.Embed embed = null;
if (mEmbeds.GetValue(lineIdx) case .Ok(out embed))
{
if ((embed.mKind == .HideLine) &&
((!IsInCollapseGroup(lineIdx, CursorLine)) || (!mEditWidget.mHasFocus)))
{
var embedRect = GetEmbedRect(lineIdx, embed);
embed.Draw(g, embedRect, true);
g.SetFont(mFont);
continue;
}
}
g.SetFont(mFont);
while (true)
{
int lineDrawEnd = lineDrawStart;
@ -481,46 +711,7 @@ namespace Beefy.theme.dark
}
if (aX != -1)
{
if (mHiliteCurrentLine && selStartIdx == selEndIdx)
{
float thickness = 2 * (lineSpacing / 18);
// This isn't quite the right value, but I'm not sure how to get this
// to properly highlight the whole line without getting cut off - this works well for now.
float totalLineWidth = mEditWidget.mScrollContentContainer.mWidth - thickness;
float x = (int)mEditWidget.mHorzPos.v; // If we don't round to int we get jitter while scrolling.
using (g.PushColor(DarkTheme.COLOR_CURRENT_LINE_HILITE))
g.OutlineRect(x, curY, totalLineWidth, lineSpacing + thickness, thickness);
}
float brightness = (float)Math.Cos(Math.Max(0.0f, mCursorBlinkTicks - 20) / 9.0f);
brightness = Math.Clamp(brightness * 2.0f + 1.6f, 0, 1);
if (mEditWidget.mVertPos.IsMoving)
brightness = 0; // When we animate a pgup or pgdn, it's weird seeing the cursor scrolling around
Color cursorColor = mTextColors[0];
if (mOverTypeMode)
{
if (mCharWidth <= 2)
{
using (g.PushColor(Color.Mult(cursorColor, Color.Get(brightness * 0.75f))))
g.FillRect(aX, curY, GS!(2), lineSpacing);
}
else
{
using (g.PushColor(Color.Mult(cursorColor, Color.Get(brightness * 0.30f))))
g.FillRect(aX, curY, mCharWidth, lineSpacing);
}
}
else
{
using (g.PushColor(Color.Mult(cursorColor, Color.Get(brightness))))
g.FillRect(aX, curY, Math.Max(1.0f, GS!(1)), lineSpacing);
}
drewCursor = true;
}
DrawCursor(aX, curY);
}
lineDrawStart = lineDrawEnd;
@ -529,6 +720,17 @@ namespace Beefy.theme.dark
if (lineDrawStart >= lineEnd)
break;
}
if (embed != null)
{
var embedRect = GetEmbedRect(lineIdx, embed);
embed.Draw(g, embedRect, false);
g.SetFont(mFont);
if ((!drewCursor) && (IsLineCollapsed(CursorLineAndColumn.mLine)) &&
(GetLineY(CursorLineAndColumn.mLine, -1) == GetLineY(lineIdx + 1, -1)))
DrawCursor(embedRect.Right + GS!(2), curY);
}
}
g.PopMatrix();
@ -561,6 +763,8 @@ namespace Beefy.theme.dark
public override void GetTextCoordAtLineChar(int line, int lineChar, out float x, out float y)
{
GetTextData();
String lineText = scope String(256);
GetLineText(line, lineText);
if (lineChar > lineText.Length)
@ -571,32 +775,63 @@ namespace Beefy.theme.dark
subText.Append(lineText, 0, lineChar);
x = GetTabbedWidth(subText, 0, true) + mTextInsets.mLeft;
}
y = mTextInsets.mTop + line * mFont.GetLineSpacing();
y = mTextInsets.mTop + mLineCoords[line];
}
public override void GetTextCoordAtLineAndColumn(int line, int column, out float x, out float y)
{
GetTextData();
Debug.Assert((mCharWidth != -1) || (column == 0));
String lineText = scope String(256);
GetLineText(line, lineText);
x = mTextInsets.mLeft + column * mCharWidth;
y = mTextInsets.mTop + line * mFont.GetLineSpacing();
y = mTextInsets.mTop + mLineCoords[line];
}
public override bool GetLineCharAtCoord(float x, float y, out int line, out int char8Idx, out float overflowX)
protected int GetLineAt(float y)
{
line = (int) ((y - mTextInsets.mTop) / mFont.GetLineSpacing() + 0.001f);
if (y < 0)
return 0;
GetTextData();
int lineCount = GetLineCount();
var checkY = y - mTextInsets.mTop + 0.001f;
var jumpEntry = mLineCoordJumpTable[Math.Clamp((int)(y / GetJumpCoordSpacing()), 0, mLineCoordJumpTable.Count - 1)];
int line = jumpEntry.min - 1;
for (int checkLine in jumpEntry.min ..< jumpEntry.max)
{
if (checkY >= mLineCoords[checkLine])
line = checkLine;
}
if (line < 0)
line = 0;
if (line >= lineCount)
line = lineCount - 1;
return line;
}
public override bool GetLineCharAtCoord(float x, float y, out int line, out int lineChar, out float overflowX)
{
line = GetLineAt(y);
return GetLineCharAtCoord(line, x, out lineChar, out overflowX);
}
public override bool GetLineAndColumnAtCoord(float x, float y, out int line, out int column)
{
line = GetLineAt(y);
column = Math.Max(0, (int32)((x - mTextInsets.mLeft + 1) / mCharWidth + 0.6f));
return mCharWidth != -1;
}
public override bool GetLineCharAtCoord(int line, float x, out int lineChar, out float overflowX)
{
String lineText = scope String(256);
GetLineText(line, lineText);
int32 char8Count = GetTabbedCharCountToLength(lineText, x - mTextInsets.mLeft);
char8Idx = char8Count;
lineChar = char8Count;
if (char8Count < lineText.Length)
{
@ -617,7 +852,7 @@ namespace Beefy.theme.dark
}
if (x >= subWidth + mTextInsets.mLeft + checkCharWidth)
char8Idx = (int32)utf8enumerator.NextIndex;
lineChar = (int32)utf8enumerator.NextIndex;
}
}
else
@ -630,16 +865,6 @@ namespace Beefy.theme.dark
return true;
}
public override bool GetLineAndColumnAtCoord(float x, float y, out int line, out int column)
{
line = (int32)((y - mTextInsets.mTop) / mFont.GetLineSpacing() + 0.001f);
if (line >= GetLineCount())
line = GetLineCount() - 1;
line = Math.Max(0, line);
column = Math.Max(0, (int32)((x - mTextInsets.mLeft + 1) / mCharWidth + 0.6f));
return mCharWidth != -1;
}
void RecalcSize(int32 startLineNum, int32 endLineNum, bool forceAccurate = false)
{
scope AutoBeefPerf("DEWC.RecalcSize");
@ -670,6 +895,53 @@ namespace Beefy.theme.dark
base.CursorToLineEnd();
}
public override void GetTextCoordAtCursor(out float x, out float y)
{
int32 line = CursorLine;
if (IsLineCollapsed(line))
{
line = (.)FindUncollapsedLine(line);
GetTextCoordAtLineAndColumn(line, CursorLineAndColumn.mColumn, out x, out y);
return;
}
base.GetTextCoordAtCursor(out x, out y);
}
public override void MoveCursorToCoord(float x, float y)
{
base.MoveCursorToCoord(x, y);
if ((!mEmbeds.IsEmpty) && (mEmbeds.GetValue(CursorLineAndColumn.mLine) case .Ok(let embed)))
{
var embedRect = GetEmbedRect(CursorLineAndColumn.mLine, embed);
if (x > embedRect.Right)
{
int endLine = CursorLineAndColumn.mLine;
while (true)
{
if (!IsLineCollapsed(endLine + 1))
break;
endLine++;
}
if (endLine != CursorLineAndColumn.mLine)
{
GetLinePosition(endLine, var endLineStart, var endLineEnd);
GetLineAndColumnAtLineChar(endLine, endLineEnd - endLineStart, var column);
CursorLineAndColumn = .(endLine, column);
}
}
}
}
public override void CursorToLineStart(bool allowToScreenStart)
{
while (IsLineCollapsed(CursorLineAndColumn.mLine))
CursorLineAndColumn = .(CursorLineAndColumn.mLine - 1, 1);
base.CursorToLineStart(allowToScreenStart);
}
public void RecalcSize(bool forceAccurate = false)
{
mMaximalScrollAddedHeight = 0;
@ -707,7 +979,9 @@ namespace Beefy.theme.dark
Debug.Assert(!mWidth.IsNaN);
}
mHeight = GetLineCount() * mFont.GetLineSpacing() + mTextInsets.mTop + mTextInsets.mBottom;
GetTextData();
mHeight = mLineCoords.Back + mTextInsets.mTop + mTextInsets.mBottom;
Debug.Assert(mHeight > 0);
UpdateMaximalScroll();
base.RecalcSize();
}
@ -721,6 +995,21 @@ namespace Beefy.theme.dark
{
base.ContentChanged();
mRecalcSizeLineNum = -1;
mLineCoordTextVersionId = -1;
DeleteAndNullify!(mLineCoords);
DeleteAndNullify!(mLineCoordJumpTable);
}
public float GetJumpCoordSpacing()
{
return mFont.GetLineSpacing() * 4;
}
public override void LineStartsChanged()
{
base.LineStartsChanged();
mLineCoordTextVersionId = -1;
}
public override void TextAppended(String str)
@ -734,7 +1023,7 @@ namespace Beefy.theme.dark
base.TextAppended(str);
}
void UpdateMaximalScroll()
protected void UpdateMaximalScroll()
{
if (mAllowMaximalScroll)
{
@ -744,6 +1033,8 @@ namespace Beefy.theme.dark
mMaximalScrollAddedHeight = mEditWidget.mScrollContentContainer.mHeight - mFont.GetLineSpacing();
mHeight += mMaximalScrollAddedHeight;
Debug.Assert(mHeight >= 0);
if (mHeight != prevHeight)
mEditWidget.UpdateScrollbars();
}
@ -757,7 +1048,9 @@ namespace Beefy.theme.dark
public override float GetLineHeight(int line)
{
return mFont.GetLineSpacing();
if (mLineCoords == null)
GetTextData();
return mLineCoords[line + 1] - mLineCoords[line];
}
public override float GetPageScrollTextHeight()
@ -843,6 +1136,27 @@ namespace Beefy.theme.dark
CheckRecordScrollTop();
}
public override void MouseMove(float x, float y)
{
base.MouseMove(x, y);
int line = GetLineAt(y);
bool isOverEmbed = false;
if (mEmbeds.GetValue(line) case .Ok(let embed))
{
Rect embedRect = GetEmbedRect(line, embed);
if (embedRect.Contains(x, y))
isOverEmbed = true;
}
if (isOverEmbed)
BFApp.sApp.SetCursor(Cursor.Pointer);
else
BFApp.sApp.SetCursor(Cursor.Text);
}
}
public class DarkEditWidget : EditWidget

View file

@ -181,6 +181,8 @@ namespace Beefy.theme.dark
PanelHeader,
ExtMethod,
CollapseClosed,
CollapseOpened,
COUNT
};

View file

@ -6,8 +6,129 @@ using System.Threading.Tasks;
namespace Beefy.utils
{
public struct IdSpan
public struct IdSpan : IFormattable
{
public class LookupContext
{
public enum SortKind
{
None,
Id,
Index
}
public struct Entry
{
public int32 mIdStart;
public int32 mIndexStart;
public int32 mLength;
}
public List<Entry> mEntries = new .() ~ delete _;
public SortKind mSortKind;
public this(IdSpan idSpan)
{
int encodeIdx = 0;
int charId = 1;
int charIdx = 0;
while (true)
{
int cmd = Utils.DecodeInt(idSpan.mData, ref encodeIdx);
if (cmd > 0)
charId = cmd;
else
{
int spanSize = -cmd;
Entry entry;
entry.mIdStart = (.)charId;
entry.mIndexStart = (.)charIdx;
entry.mLength = (.)spanSize;
mEntries.Add(entry);
charId += spanSize;
charIdx += spanSize;
if (cmd == 0)
break;
}
}
}
public int GetIndexFromId(int32 findCharId)
{
if (mSortKind != .Id)
{
mEntries.Sort(scope (lhs, rhs) => lhs.mIdStart <=> rhs.mIdStart);
mSortKind = .Id;
}
int lo = 0;
int hi = mEntries.Count - 1;
while (lo <= hi)
{
int i = (lo + hi) / 2;
var midVal = ref mEntries[i];
if ((findCharId >= midVal.mIdStart) && (findCharId < midVal.mIdStart + midVal.mLength))
return midVal.mIndexStart + (findCharId - midVal.mIdStart);
if (findCharId > midVal.mIdStart)
lo = i + 1;
else
hi = i - 1;
}
return -1;
}
public int32 GetIdAtIndex(int32 findCharId)
{
if (mSortKind != .Index)
{
mEntries.Sort(scope (lhs, rhs) => lhs.mIndexStart <=> rhs.mIndexStart);
mSortKind = .Index;
}
int lo = 0;
int hi = mEntries.Count - 1;
while (lo <= hi)
{
int i = (lo + hi) / 2;
var midVal = ref mEntries[i];
if ((findCharId >= midVal.mIndexStart) && (findCharId < midVal.mIndexStart + midVal.mLength))
return midVal.mIdStart + (findCharId - midVal.mIndexStart);
if (findCharId > midVal.mIndexStart)
lo = i + 1;
else
hi = i - 1;
}
return -1;
}
public override void ToString(String strBuffer)
{
if (mSortKind != .Index)
{
mEntries.Sort(scope (lhs, rhs) => lhs.mIndexStart <=> rhs.mIndexStart);
mSortKind = .Index;
}
strBuffer.AppendF("IdSpan.LookupCtx(");
for (var entry in mEntries)
{
if (@entry.Index > 0)
strBuffer.Append(' ');
strBuffer.AppendF($"{entry.mIndexStart}:{entry.mLength}={entry.mIdStart}");
}
strBuffer.AppendF(")");
}
}
enum Change
{
case Insert(int32 index, int32 id, int16 length);
@ -671,7 +792,6 @@ namespace Beefy.utils
public IdSpan Duplicate()
{
Debug.Assert(!HasChangeList);
IdSpan idSpan = IdSpan();
if (mData != null)
{
@ -679,6 +799,12 @@ namespace Beefy.utils
mData.CopyTo(idSpan.mData, 0, 0, mLength);
idSpan.mLength = mLength;
}
if (mChangeList != null)
{
idSpan.mChangeList = new .();
for (var change in mChangeList)
idSpan.mChangeList.Add(change);
}
return idSpan;
}
@ -866,6 +992,11 @@ namespace Beefy.utils
return idSpan;
}
public override void ToString(String strBuffer)
{
ToString(strBuffer, "", null);
}
public void Dump() mut
{
Prepare();
@ -895,5 +1026,49 @@ namespace Beefy.utils
}
}
}
public void ToString(String outString, String format, IFormatProvider formatProvider)
{
if (HasChangeList)
{
IdSpan span = Duplicate();
span.ToString(outString, format, formatProvider);
return;
}
outString.AppendF($"Span(Length:{mLength} ChangeList:{(mChangeList?.Count).GetValueOrDefault()})");
if (format == "D")
{
outString.Append("{");
int encodeIdx = 0;
int charId = 1;
int charIdx = 0;
while (true)
{
int32 cmd = Utils.DecodeInt(mData, ref encodeIdx);
if (cmd > 0)
{
charId = cmd;
outString.AppendF($" #{charId}");
}
else
{
int32 spanSize = -cmd;
charId += spanSize;
charIdx += spanSize;
if (cmd == 0)
{
outString.Append("}");
return;
}
outString.AppendF($":{spanSize}");
}
}
}
}
}
}

View file

@ -576,11 +576,11 @@ namespace Beefy.widgets
float y;
GetTextCoordAtLineAndColumn(mVirtualCursorPos.Value.mLine, mVirtualCursorPos.Value.mColumn, out x, out y);
int line;
int lineChar;
float overflowX;
GetLineCharAtCoord(x, y, out line, out lineChar, out overflowX);
mCursorTextPos = (int32)GetTextIdx(line, lineChar);
GetLineCharAtCoord(mVirtualCursorPos.Value.mLine, x, out lineChar, out overflowX);
mCursorTextPos = (int32)GetTextIdx(mVirtualCursorPos.Value.mLine, lineChar);
}
return mCursorTextPos;
@ -606,14 +606,9 @@ namespace Beefy.widgets
int lineChar;
GetLineCharAtIdx(mCursorTextPos, out line, out lineChar);
float x;
float y;
GetTextCoordAtLineChar(line, lineChar, out x, out y);
int coordLine;
int coordLineColumn;
GetLineAndColumnAtCoord(x, y, out coordLine, out coordLineColumn);
lineAndColumn.mLine = (int32)coordLine;
GetLineAndColumnAtLineChar(line, lineChar, out coordLineColumn);
lineAndColumn.mLine = (int32)line;
lineAndColumn.mColumn = (int32)coordLineColumn;
return lineAndColumn;
}
@ -627,6 +622,20 @@ namespace Beefy.widgets
}
}
public int32 CursorLine
{
get
{
if (mVirtualCursorPos.HasValue)
return mVirtualCursorPos.Value.mLine;
int line;
int lineChar;
GetLineCharAtIdx(mCursorTextPos, out line, out lineChar);
return (.)line;
}
}
public bool WantsUndo
{
get
@ -645,6 +654,7 @@ namespace Beefy.widgets
mContentChanged = true;
}
protected virtual Data CreateEditData()
{
return new Data();
@ -661,13 +671,13 @@ namespace Beefy.widgets
{
if (mVirtualCursorPos.HasValue)
{
int32 line = mVirtualCursorPos.Value.mLine;
float x;
float y;
GetTextCoordAtLineAndColumn(mVirtualCursorPos.Value.mLine, mVirtualCursorPos.Value.mColumn, out x, out y);
GetTextCoordAtLineAndColumn(line, mVirtualCursorPos.Value.mColumn, out x, out y);
int line;
int lineChar;
bool success = GetLineCharAtCoord(x, y, out line, out lineChar, out overflowX);
bool success = GetLineCharAtCoord(line, x, out lineChar, out overflowX);
textPos = GetTextIdx(line, lineChar);
return success;
@ -1342,6 +1352,11 @@ namespace Beefy.widgets
mEditWidget.ContentChanged();
TextChanged();
}
public virtual void LineStartsChanged()
{
}
public virtual void TextAppended(String str)
@ -1366,6 +1381,7 @@ namespace Beefy.widgets
}
}
mData.mLineStarts.Add(mData.mTextLength);
LineStartsChanged();
mContentChanged = true;
@ -1385,8 +1401,9 @@ namespace Beefy.widgets
{
// Generate line starts and text flags if we need to
if (mData.mLineStarts == null)
{
if (mData.mLineStarts != null)
return;
scope AutoBeefPerf("EWC.GetTextData");
CharData* char8DataPtr = mData.mText.CArray();
@ -1447,7 +1464,7 @@ namespace Beefy.widgets
}
mData.mLineStarts[lineIdx + 1] = mData.mTextLength;
}
LineStartsChanged();
}
public virtual void Backspace()
@ -1519,7 +1536,7 @@ namespace Beefy.widgets
ContentChanged();
if (offset != 0)
{
MoveCursorToIdx(textPos, false, .FromTyping);
MoveCursorToIdx(textPos, false, .FromTyping_Deleting);
EnsureCursorVisible();
}
}
@ -1648,7 +1665,7 @@ namespace Beefy.widgets
}
else
{
int32 char8Count = 1;
int32 charCount = 1;
int checkIdx = textPos + 1;
while (true)
{
@ -1660,12 +1677,12 @@ namespace Beefy.widgets
if (!checkChar.IsCombiningMark)
break;
}
char8Count++;
charCount++;
checkIdx++;
}
mData.mUndoManager.Add(new DeleteCharAction(this, 0, char8Count));
PhysDeleteChars(0, char8Count);
mData.mUndoManager.Add(new DeleteCharAction(this, 0, charCount));
PhysDeleteChars(0, charCount);
}
}
@ -1934,7 +1951,7 @@ namespace Beefy.widgets
return .Other;
}
public void GetTextCoordAtCursor(out float x, out float y)
public virtual void GetTextCoordAtCursor(out float x, out float y)
{
if (mVirtualCursorPos.HasValue)
{
@ -1963,8 +1980,9 @@ namespace Beefy.widgets
float y;
GetTextCoordAtLineAndColumn(mVirtualCursorPos.Value.mLine, mVirtualCursorPos.Value.mColumn, out x, out y);
float overflowX;
return GetLineCharAtCoord(x, y, out line, out lineChar, out overflowX);
return GetLineCharAtCoord(line, x, out lineChar, out overflowX);
}
public virtual bool PrepareForCursorMove(int dir = 0)
@ -2064,6 +2082,7 @@ namespace Beefy.widgets
if (var insertTextAction = mData.mUndoManager.GetLastUndoAction() as InsertTextAction)
insertTextAction.mVirtualCursorPos = origPosition;
CursorLineAndColumn = lineStartPosition;
CursorToLineStart(false);
// Adjust to requested column
@ -2110,15 +2129,15 @@ namespace Beefy.widgets
while (true)
{
if (lineChar > 0)
MoveCursorTo(lineIdx, lineChar - 1);
MoveCursorTo(lineIdx, lineChar - 1, false, 0, .SelectLeft);
else if (lineIdx > 0)
{
int cursorIdx = mCursorTextPos;
String lineText = scope String();
GetLineText(lineIdx - 1, lineText);
MoveCursorTo(lineIdx - 1, (int32)lineText.Length);
MoveCursorTo(lineIdx - 1, (int32)lineText.Length, false, 0, .SelectLeft);
if ((!mAllowVirtualCursor) && (cursorIdx == mCursorTextPos))
MoveCursorTo(lineIdx - 1, (int32)lineText.Length - 1);
MoveCursorTo(lineIdx - 1, (int32)lineText.Length - 1, false, 0, .SelectLeft);
break;
}
@ -2180,9 +2199,9 @@ namespace Beefy.widgets
}
if (isWithinLine)
MoveCursorTo(lineIdx, lineChar + 1, false, 1);
MoveCursorTo(lineIdx, lineChar + 1, false, 1, .SelectRight);
else if (lineIdx < GetLineCount() - 1)
MoveCursorTo(lineIdx + 1, 0);
MoveCursorTo(lineIdx + 1, 0, false, 0, .SelectRight);
if (!mWidgetWindow.IsKeyDown(KeyCode.Control))
break;
@ -2349,7 +2368,7 @@ namespace Beefy.widgets
var lineAndColumn = CursorLineAndColumn;
CursorLineAndColumn = LineAndColumn(lineAndColumn.mLine, lineAndColumn.mColumn + 1);
EnsureCursorVisible(true, false, false);
CursorMoved();
PhysCursorMoved(.SelectRight);
ClampCursor();
if (lineAndColumn != CursorLineAndColumn)
@ -2393,22 +2412,40 @@ namespace Beefy.widgets
wasMoveKey = true;
if ((lineIdx + aDir >= 0) && (lineIdx + aDir < GetLineCount()))
{
float wantedX = mCursorWantX;
float wantY = 0;
if (mAllowVirtualCursor)
{
float cursorX;
float cursorY;
GetTextCoordAtCursor(out cursorX, out cursorY);
GetLineAndColumnAtCoord(cursorX, cursorY, var virtLine, ?);
/*GetTextCoordAtLineAndColumn(lineIdx, 0, ?, var lineY);
Debug.WriteLine($"Line:{lineIdx} LineY:{lineY} Cursor:{cursorX},{cursorY}");*/
if (aDir < 0)
{
wantY = cursorY - 0.1f;
}
else
{
wantY = cursorY + GetLineHeight(virtLine) + 0.1f;
}
//mCursorWantX = cursorX;
}
else
{
lineIdx += aDir;
float wantedX = mCursorWantX;
float aX;
float aY;
GetTextCoordAtLineChar(lineIdx, 0, out aX, out aY);
MoveCursorToCoord(mCursorWantX, aY);
wantY = aY;
}
MoveCursorToCoord(mCursorWantX, wantY);
ClampCursor();
@ -2645,6 +2682,12 @@ namespace Beefy.widgets
return false;
}
public virtual bool GetLineCharAtCoord(int line, float x, out int theChar, out float overflowX)
{
GetTextCoordAtLineAndColumn(line, 0, ?, var y);
return GetLineCharAtCoord(x, y, ?, out theChar, out overflowX);
}
public virtual bool GetLineAndColumnAtCoord(float x, float y, out int line, out int column)
{
line = -1;
@ -2818,11 +2861,11 @@ namespace Beefy.widgets
ExtractString(lineStart, lineEnd - lineStart, outStr); // Full line
}
public int GetTextIdx(int line, int char8Idx)
public int GetTextIdx(int line, int charIdx)
{
GetTextData();
int useLine = Math.Min(line, mData.mLineStarts.Count - 1);
return mData.mLineStarts[useLine] + char8Idx;
return mData.mLineStarts[useLine] + charIdx;
}
public int GetCharIdIdx(int32 findCharId)
@ -2839,7 +2882,7 @@ namespace Beefy.widgets
int curLine = 0;
int curColumn = 0;
int char8Idx = 0;
int charIdx = 0;
mData.mTextIdData.Prepare();
while (true)
{
@ -2863,7 +2906,7 @@ namespace Beefy.widgets
if ((curLine == line) && (curColumn == column))
return char8Id;
char8 c = (char8)mData.mText[char8Idx++].mChar;
char8 c = (char8)mData.mText[charIdx++].mChar;
if (c == '\n')
{
if (curLine == line)
@ -2878,7 +2921,7 @@ namespace Beefy.widgets
}
}
public virtual void GetTextCoordAtLineChar(int line, int char8Idx, out float x, out float y)
public virtual void GetTextCoordAtLineChar(int line, int charIdx, out float x, out float y)
{
x = 0;
y = 0;
@ -2892,8 +2935,13 @@ namespace Beefy.widgets
public enum CursorMoveKind
{
FromTyping,
Unknown
case FromTyping;
case FromTyping_Deleting;
case Unknown;
case SelectRight;
case SelectLeft;
public bool IsFromTyping => (this == FromTyping) || (this == FromTyping_Deleting);
}
// We used to have a split between PhysCursorMoved and CursorMoved. CursorMoved has a "ResetWantX" and was non-virtual... uh-
@ -3379,14 +3427,22 @@ namespace Beefy.widgets
Debug.Assert(mSelection.Value.mEndPos <= mData.mTextLength);
}
//public void MoveCursorTo
public void MoveCursorTo(int line, int char8Idx, bool centerCursor = false, int movingDir = 0, CursorMoveKind cursorMoveKind = .Unknown)
public virtual void GetLineAndColumnAtLineChar(int line, int lineChar, out int lineColumn)
{
int useCharIdx = char8Idx;
float x;
float y;
GetTextCoordAtLineChar(line, lineChar, out x, out y);
int coordLine;
GetLineAndColumnAtCoord(x, y, out coordLine, out lineColumn);
}
public virtual void MoveCursorTo(int line, int charIdx, bool centerCursor = false, int movingDir = 0, CursorMoveKind cursorMoveKind = .Unknown)
{
int useCharIdx = charIdx;
mShowCursorAtLineEnd = false;
CursorTextPos = GetTextIdx(line, char8Idx);
CursorTextPos = GetTextIdx(line, charIdx);
// Skip over UTF8 parts AND unicode combining marks (ie: when we have a letter with an accent mark following it)
while (true)
@ -3433,13 +3489,13 @@ namespace Beefy.widgets
public void MoveCursorToIdx(int index, bool centerCursor = false, CursorMoveKind cursorMoveKind = .Unknown)
{
int aLine;
int aCharIdx;
GetLineCharAtIdx(index, out aLine, out aCharIdx);
MoveCursorTo(aLine, aCharIdx, centerCursor, 0, cursorMoveKind);
int line;
int charIdx;
GetLineCharAtIdx(index, out line, out charIdx);
MoveCursorTo(line, charIdx, centerCursor, 0, cursorMoveKind);
}
public void MoveCursorToCoord(float x, float y)
public virtual void MoveCursorToCoord(float x, float y)
{
bool failed = false;

View file

@ -822,6 +822,20 @@ namespace System.Collections
return false;
}
public bool TryGetRef(TKey key, out TKey* matchKey, out TValue* value)
{
int_cosize i = (int_cosize)FindEntry(key);
if (i >= 0)
{
matchKey = &mEntries[i].mKey;
value = &mEntries[i].mValue;
return true;
}
matchKey = null;
value = null;
return false;
}
public bool TryGetAlt<TAltKey>(TAltKey key, out TKey matchKey, out TValue value) where TAltKey : IHashable where bool : operator TKey == TAltKey
{
int_cosize i = (int_cosize)FindEntryAlt(key);
@ -836,6 +850,20 @@ namespace System.Collections
return false;
}
public bool TryGetRefAlt<TAltKey>(TAltKey key, out TKey* matchKey, out TValue* value) where TAltKey : IHashable where bool : operator TKey == TAltKey
{
int_cosize i = (int_cosize)FindEntryAlt(key);
if (i >= 0)
{
matchKey = &mEntries[i].mKey;
value = &mEntries[i].mValue;
return true;
}
matchKey = null;
value = null;
return false;
}
public TValue GetValueOrDefault(TKey key)
{
int_cosize i = (int_cosize)FindEntry(key);
@ -1024,7 +1052,7 @@ namespace System.Collections
private int_cosize mVersion;
#endif
private int_cosize mIndex;
private TValue mCurrent;
private TValue* mCurrent;
const int_cosize cDictEntry = 1;
const int_cosize cKeyValuePair = 2;
@ -1051,7 +1079,7 @@ namespace System.Collections
{
if (mDictionary.mEntries[mIndex].mHashCode >= 0)
{
mCurrent = mDictionary.mEntries[mIndex].mValue;
mCurrent = &mDictionary.mEntries[mIndex].mValue;
mIndex++;
return true;
}
@ -1065,12 +1093,12 @@ namespace System.Collections
public TValue Current
{
get { return mCurrent; }
get { return *mCurrent; }
}
public ref TValue CurrentRef
{
get mut { return ref mCurrent; }
get mut { return ref *mCurrent; }
}
public ref TKey Key
@ -1128,7 +1156,7 @@ namespace System.Collections
}
}
public struct KeyEnumerator : IEnumerator<TKey>, IResettable
public struct KeyEnumerator : IEnumerator<TKey>, IRefEnumerator<TKey*>, IResettable
{
private Dictionary<TKey, TValue> mDictionary;
#if VERSION_DICTIONARY
@ -1187,6 +1215,11 @@ namespace System.Collections
get { return *mCurrent; }
}
public ref TKey CurrentRef
{
get { return ref *mCurrent; }
}
public ref TValue Value
{
get
@ -1224,6 +1257,13 @@ namespace System.Collections
return .Err;
return Current;
}
public Result<TKey*> GetNextRef() mut
{
if (!MoveNext())
return .Err;
return &CurrentRef;
}
}
}
}

View file

@ -536,6 +536,15 @@ namespace System.Collections
EnsureCapacity(size, true);
}
public void Resize(int size)
{
EnsureCapacity(size, true);
int addSize = size - mSize;
if (addSize > 0)
Internal.MemSet(Ptr + mSize, 0, addSize * alignof(T));
mSize = (.)size;
}
public Enumerator GetEnumerator()
{
return Enumerator(this);
@ -716,6 +725,13 @@ namespace System.Collections
sorter.[Friend]Sort(0, mSize);
}
public void Sort(Comparison<T> comp, int index, int count)
{
Debug.Assert((uint)index + (uint)count <= (uint)mSize);
var sorter = Sorter<T, void>(mItems, null, mSize, comp);
sorter.[Friend]Sort(index, count);
}
public int RemoveAll(Predicate<T> match)
{
int_cosize freeIndex = 0; // the first free slot in items array

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before After
Before After

View file

@ -214,6 +214,12 @@ namespace IDE
Add("Close Document", new () => { gApp.[Friend]TryCloseCurrentDocument(); });
Add("Close Panel", new () => { gApp.[Friend]TryCloseCurrentPanel(); });
Add("Close Workspace", new => gApp.[Friend]Cmd_CloseWorkspaceAndSetupNew);
Add("Collapse All", new => gApp.[Friend]CollapseAll);
Add("Collapse To Definition", new => gApp.[Friend]CollapseToDefinition);
Add("Collapse Redo", new => gApp.[Friend]CollapseRedo);
Add("Collapse Toggle", new => gApp.[Friend]CollapseToggle);
Add("Collapse Toggle All", new => gApp.[Friend]CollapseToggleAll);
Add("Collapse Undo", new => gApp.[Friend]CollapseUndo);
Add("Comment Block", new => gApp.[Friend]CommentBlock, .Editor);
Add("Comment Lines", new => gApp.[Friend]CommentLines, .Editor);
Add("Comment Toggle", new => gApp.[Friend]CommentToggle, .Editor);

View file

@ -60,6 +60,9 @@ namespace IDE.Compiler
[CallingConvention(.Stdcall), CLink]
static extern bool BfCompiler_ClassifySource(void* bfCompiler, void* bfPassInstance, void* bfParser, void* bfResolvePassData, void* char8Data);
[CallingConvention(.Stdcall), CLink]
static extern char8* BfCompiler_GetCollapseRegions(void* bfCompiler, void* bfParser);
[CallingConvention(.Stdcall), CLink]
static extern char8* BfCompiler_GetAutocompleteInfo(void* bfCompiler);
@ -266,6 +269,11 @@ namespace IDE.Compiler
return BfCompiler_ClassifySource(mNativeBfCompiler, bfPassInstance.mNativeBfPassInstance, (parser != null) ? parser.mNativeBfParser : null, nativeResolvePassData, char8DataPtr);
}
public void GetCollapseRegions(BfParser parser, String outData)
{
outData.Append(BfCompiler_GetCollapseRegions(mNativeBfCompiler, (parser != null) ? parser.mNativeBfParser : null));
}
public bool VerifyTypeName(String typeName, int cursorPos)
{
return BfCompiler_VerifyTypeName(mNativeBfCompiler, typeName, (.)cursorPos);

View file

@ -2439,6 +2439,42 @@ namespace IDE
//FinishShowingNewWorkspace();
}
[IDECommand]
void CollapseAll()
{
GetActiveSourceEditWidgetContent()?.CollapseAll();
}
[IDECommand]
void CollapseToDefinition()
{
GetActiveSourceEditWidgetContent()?.CollapseToDefinition();
}
[IDECommand]
void CollapseRedo()
{
}
[IDECommand]
void CollapseToggle()
{
GetActiveSourceEditWidgetContent()?.CollapseToggle();
}
[IDECommand]
void CollapseToggleAll()
{
GetActiveSourceEditWidgetContent()?.CollapseToggleAll();
}
[IDECommand]
void CollapseUndo()
{
}
[IDECommand]
void DeleteAllRight()
{
@ -2485,6 +2521,73 @@ namespace IDE
sewc.ToggleComment(false);
}
[IDECommand]
void ComplexIdSpan()
{
if (var sourceViewPanel = GetLastActiveDocumentPanel() as SourceViewPanel)
{
var sewc = sourceViewPanel.mEditWidget.mEditWidgetContent as SourceEditWidgetContent;
uint8[] newData = new uint8[sewc.mData.mTextLength*4];
var idData = ref sewc.mData.mTextIdData;
/*idData.Prepare();
int encodeIdx = 0;
int decodeIdx = 0;
int charId = 1;
int charIdx = 0;
while (true)
{
int32 cmd = Utils.DecodeInt(idData.mData, ref decodeIdx);
if (cmd > 0)
{
charId = cmd;
Utils.EncodeInt(newData, ref encodeIdx, charId);
}
else
{
int32 spanSize = -cmd;
charId += spanSize;
charIdx += spanSize;
if (cmd == 0)
{
Utils.EncodeInt(newData, ref encodeIdx, 0);
break;
}
while (spanSize > 65)
{
Utils.EncodeInt(newData, ref encodeIdx, -64);
spanSize -= 64;
}
Utils.EncodeInt(newData, ref encodeIdx, -spanSize);
}
}*/
int encodeIdx = 0;
int sizeLeft = sewc.mData.mTextLength;
while (sizeLeft > 0)
{
int writeLength = Math.Min(sizeLeft, 64);
Utils.EncodeInt(newData, ref encodeIdx, sewc.mData.mNextCharId);
Utils.EncodeInt(newData, ref encodeIdx, -writeLength);
sewc.mData.mNextCharId += (.)writeLength;
sewc.mData.mNextCharId++;
sizeLeft -= writeLength;
}
Utils.EncodeInt(newData, ref encodeIdx, 0);
IdSpan newSpan = .(newData, (.)encodeIdx);
//Runtime.Assert(newSpan.Equals(idData));
idData.Dispose();
idData = newSpan;
}
}
public Result<void, StructuredData.Error> StructuredLoad(StructuredData data, StringView filePath)
{
if (mWorkspace.IsSingleFileWorkspace)

View file

@ -2583,6 +2583,30 @@ namespace IDE
#endif
}
[IDECommand]
public void UndoFill()
{
var documentPanel = gApp.GetLastActiveDocumentPanel();
if (var sourceViewPanel = documentPanel as SourceViewPanel)
{
int count = 0;
for (int i < 400)
{
for (char8 c = 'A'; c <= 'Z'; c++)
{
String str = scope .(32);
if (count++ % 131 == 0)
str.Append("\n//");
str.Append(c);
sourceViewPanel.mEditWidget.mEditWidgetContent.mData.mUndoManager.[Friend]mSkipNextMerge = true;
sourceViewPanel.mEditWidget.mEditWidgetContent.InsertAtCursor(str);
}
}
}
}
[IDECommand]
public void SetVal(String valName, String value)
{

View file

@ -774,6 +774,12 @@ namespace IDE
Add("Build Workspace", "F7");
Add("Cancel Build", "Ctrl+Break");
Add("Close Document", "Ctrl+W");
Add("Collapse All", "Ctrl+M, Ctrl+A");
Add("Collapse To Definition", "Ctrl+M, Ctrl+O");
Add("Collapse Redo", "Ctrl+M, Ctrl+Y");
Add("Collapse Toggle", "Ctrl+M, Ctrl+M");
Add("Collapse Toggle All", "Ctrl+M, Ctrl+L");
Add("Collapse Undo", "Ctrl+M, Ctrl+Z");
Add("Compile File", "Ctrl+F7");
Add("Comment Block", "Ctrl+K, Ctrl+C");
Add("Comment Lines", "Ctrl+K, Ctrl+/");

View file

@ -85,7 +85,7 @@ namespace IDE.ui
public bool mIsReplace;
public int32 mLastTextVersion;
bool mFoundMatches;
bool mIsShowingMatches = false;
public bool mIsShowingMatches = false;
static String sLastSearchString = new String() ~ delete _;
public bool mOwnsSelection;

File diff suppressed because it is too large Load diff

View file

@ -165,7 +165,7 @@ namespace IDE.ui
public ~this()
{
NOP!();
}
}
@ -300,6 +300,35 @@ namespace IDE.ui
public int32 mDebuggerContinueIdx;
}
class CollapseRegionView
{
public const uint32 cStartFlag = 0x8000'0000;
public const uint32 cMidFlag = 0x4000'0000;
public const uint32 cEndFlag = 0x2000'0000;
public const uint32 cIdMask = 0x0FFF'FFFF;
public List<uint32> mCollapseIndices = new .() ~ delete _;
public int32 mLineStart;
public int32 mCollapseRevision;
public int32 mTextVersionId;
public uint32 GetCollapseValue(int param)
{
if (param < mLineStart)
return 0;
if (param - mLineStart < mCollapseIndices.Count)
return mCollapseIndices[param - mLineStart];
return 0;
}
}
class QueuedCollapseData
{
public String mData = new .() ~ delete _;
public int32 mTextVersion;
public IdSpan mCharIdSpan ~ _.Dispose();
}
public class SourceViewPanel : TextPanel
{
enum SourceDisplayId
@ -349,9 +378,12 @@ namespace IDE.ui
int32 mTicksSinceTextChanged;
int32 mErrorLookupTextIdx = -1;
LinePointerDrawData mLinePointerDrawData;
Point? mMousePos;
#if IDE_C_SUPPORT
public String mClangHoverErrorData ~ delete mClangHoverErrorData;
#endif
CollapseRegionView mCollapseRegionView = new .() ~ delete _;
QueuedCollapseData mQueuedCollapseData ~ delete _;
public EditWidgetContent.CharData[] mProcessSpellCheckCharData ~ delete _;
public IdSpan mProcessSpellCheckCharIdSpan ~ _.Dispose();
@ -1785,18 +1817,18 @@ namespace IDE.ui
parser = bfSystem.CreateEmptyParser((BfProject)null);
}
EditWidgetContent.CharData[] char8Data = null;
int char8Len = 0;
EditWidgetContent.CharData[] charData = null;
int charLen = 0;
if ((resolveParams != null) && (resolveParams.mCharData != null))
{
char8Data = resolveParams.mCharData;
char8Len = resolveParams.mCharData.Count;
charData = resolveParams.mCharData;
charLen = resolveParams.mCharData.Count;
}
if (char8Data == null)
if (charData == null)
{
Debug.Assert(!isBackground);
char8Data = mEditWidget.Content.mData.mText;
char8Len = mEditWidget.Content.mData.mTextLength;
charData = mEditWidget.Content.mData.mText;
charLen = mEditWidget.Content.mData.mTextLength;
}
/*var char8Data = (!isBackground) ? mEditWidget.Content.mData.mText : mProcessResolveCharData;
@ -1818,12 +1850,12 @@ namespace IDE.ui
if (!isBackground)
bfSystem.PerfZoneStart("DoClassify.CreateChars");
char8[] chars = new char8[char8Len];
char8[] chars = new char8[charLen];
defer delete chars;
for (int32 i = 0; i < char8Len; i++)
for (int32 i = 0; i < charLen; i++)
{
char8Data[i].mDisplayPassId = (int32)SourceDisplayId.Cleared;
chars[i] = (char8)char8Data[i].mChar;
charData[i].mDisplayPassId = (int32)SourceDisplayId.Cleared;
chars[i] = (char8)charData[i].mChar;
}
String text = scope String();
@ -1933,7 +1965,7 @@ namespace IDE.ui
if ((!isFastClassify) && (bfCompiler != null))
{
if (!bfCompiler.ClassifySource(passInstance, parser, resolvePassData, char8Data))
if (!bfCompiler.ClassifySource(passInstance, parser, resolvePassData, charData))
{
//DeleteAndNullify!(mProcessResolveCharData);
//mProcessResolveCharIdSpan.Dispose();
@ -1945,10 +1977,23 @@ namespace IDE.ui
}
bfCompiler.QueueDeferredResolveAll();
}
if ((resolveType == ResolveType.Classify) || (resolveType == ResolveType.ClassifyFullRefresh))
{
var collapseData = bfCompiler.GetCollapseRegions(parser, .. scope .());
using (mMonitor.Enter())
{
DeleteAndNullify!(mQueuedCollapseData);
mQueuedCollapseData = new .();
mQueuedCollapseData.mData.Set(collapseData);
mQueuedCollapseData.mTextVersion = resolveParams.mTextVersion;
mQueuedCollapseData.mCharIdSpan = resolveParams.mCharIdSpan.Duplicate();
}
}
}
else
{
parser.ClassifySource(char8Data, !mIsBeefSource);
parser.ClassifySource(charData, !mIsBeefSource);
}
if (!isBackground)
@ -3637,6 +3682,18 @@ namespace IDE.ui
AddWidget(mSplitTopPanel);
var ewc = (SourceEditWidgetContent)mEditWidget.mEditWidgetContent;
var topEWC = (SourceEditWidgetContent)mSplitTopPanel.mEditWidget.mEditWidgetContent;
for (var entry in ewc.mOrderedCollapseEntries)
{
if (!entry.mIsOpen)
{
topEWC.SetCollapseOpen(@entry.Index, false, true);
}
}
topEWC.RehupLineCoords();
ResizeComponents();
// Match scroll positions
@ -4106,7 +4163,8 @@ namespace IDE.ui
if (mLoadFailed)
return;
DarkEditWidgetContent darkEditWidgetContent = (DarkEditWidgetContent)mEditWidget.Content;
var ewc = (SourceEditWidgetContent)mEditWidget.Content;
ewc.GetTextData();
g.SetFont(IDEApp.sApp.mTinyCodeFont);
@ -4115,13 +4173,93 @@ namespace IDE.ui
using (g.PushTranslate(0, mEditWidget.mY + mEditWidget.Content.Y + GS!(2)))
{
float editX = GetEditX();
float lineSpacing = darkEditWidgetContent.mFont.GetLineSpacing();
int cursorLineNumber = mEditWidget.mEditWidgetContent.CursorLineAndColumn.mLine;
using (g.PushColor(gApp.mSettings.mUISettings.mColors.mCurrentLineNumberHilite))
g.FillRect(0, GS!(2) + cursorLineNumber * lineSpacing, editX - GS!(2), lineSpacing);
float leftAdjust = GS!(12);
float lineSpacing = ewc.mFont.GetLineSpacing();
int cursorLineNumber = mEditWidget.mEditWidgetContent.CursorLineAndColumn.mLine;
bool hiliteCurrentLine = true;
var jumpEntry = ewc.mLineCoordJumpTable[Math.Clamp((int)(-mEditWidget.Content.Y / ewc.GetJumpCoordSpacing()), 0, ewc.mLineCoordJumpTable.Count - 1)];
int lineStart = jumpEntry.min;
jumpEntry = ewc.mLineCoordJumpTable[Math.Clamp((int)((-mEditWidget.Content.Y + mHeight) / ewc.GetJumpCoordSpacing()), 0, ewc.mLineCoordJumpTable.Count - 1)];
int lineEnd = jumpEntry.max - 1;
int drawLineCount = lineEnd - lineStart + 1;
ewc.RefreshCollapseRegions();
if ((mCollapseRegionView.mLineStart != lineStart) || (mCollapseRegionView.mCollapseIndices.Count != drawLineCount) ||
(mCollapseRegionView.mCollapseRevision != ewc.mCollapseParseRevision) || (mCollapseRegionView.mTextVersionId != ewc.mCollapseTextVersionId))
{
mCollapseRegionView.mLineStart = (.)lineStart;
mCollapseRegionView.mCollapseIndices.Clear();
Internal.MemSet(mCollapseRegionView.mCollapseIndices.GrowUnitialized(drawLineCount), 0, drawLineCount * sizeof(int32));
mCollapseRegionView.mCollapseRevision = ewc.mCollapseParseRevision;
mCollapseRegionView.mTextVersionId = ewc.mCollapseTextVersionId;
List<int32> collapseStack = scope .(16);
int32 curIdx = 0;
for (int line in lineStart...lineEnd)
{
uint32 indexVal = 0;
while (curIdx < ewc.mOrderedCollapseEntries.Count)
{
var entry = ewc.mOrderedCollapseEntries[curIdx];
if (entry.mAnchorLine > line)
break;
if (!entry.mDeleted)
{
indexVal = (uint32)curIdx | CollapseRegionView.cStartFlag;
collapseStack.Add(curIdx);
}
curIdx++;
}
while (!collapseStack.IsEmpty)
{
var entry = ewc.mOrderedCollapseEntries[collapseStack.Back];
if (line < entry.mEndLine)
break;
if (indexVal == 0)
indexVal = (uint32)collapseStack.Back | CollapseRegionView.cEndFlag;
collapseStack.PopBack();
}
if ((indexVal == 0) && (!collapseStack.IsEmpty))
indexVal = (uint32)collapseStack.Back | CollapseRegionView.cMidFlag;
mCollapseRegionView.mCollapseIndices[line - lineStart] = indexVal;
}
}
if ((mMousePos != null) && (mMousePos.Value.x >= mEditWidget.mX - GS!(13)) && (mMousePos.Value.x < mEditWidget.mX - GS!(0)))
{
int lineClick = GetLineAt(0, mMousePos.Value.y);
uint32 collapseVal = mCollapseRegionView.GetCollapseValue(lineClick);
if (collapseVal != 0)
{
var entry = ewc.mOrderedCollapseEntries[collapseVal & CollapseRegionView.cIdMask];
float startY = ewc.mLineCoords[entry.mAnchorLine];
float endY = ewc.mLineCoords[entry.mEndLine + 1];
using (g.PushColor(gApp.mSettings.mUISettings.mColors.mCurrentLineNumberHilite))
g.FillRect(0, GS!(2) + startY, editX - GS!(10), endY - startY);
hiliteCurrentLine = false;
}
}
if (hiliteCurrentLine)
{
using (g.PushColor(gApp.mSettings.mUISettings.mColors.mCurrentLineNumberHilite))
{
int hiliteLineNum = cursorLineNumber;
while (ewc.IsLineCollapsed(hiliteLineNum))
hiliteLineNum--;
g.FillRect(0, GS!(2) + ewc.mLineCoords[hiliteLineNum], editX - GS!(10), lineSpacing);
}
}
int lineStart = (int)((-mEditWidget.Content.Y) / lineSpacing) - 1;
int lineEnd = Math.Min(darkEditWidgetContent.GetLineCount(), lineStart + (int)(mHeight / lineSpacing) + 3);
if (lineEnd <= lineStart)
{
return;
@ -4144,8 +4282,8 @@ namespace IDE.ui
int breakpointCount = (.)(curLineFlags & .BreakpointCountMask);
curLineFlags++;
float iconX = Math.Max(GS!(-2), mEditWidget.mX - GS!(24)) + breakpointCount*-GS!(2);
float iconY = 0 + drawLineNum * lineSpacing + (lineSpacing - DarkTheme.sUnitSize + GS!(5)) / 2;
float iconX = Math.Max(GS!(-2), mEditWidget.mX - GS!(24) - leftAdjust) + breakpointCount*-GS!(2);
float iconY = 0 + ewc.mLineCoords[drawLineNum] + (lineSpacing - DarkTheme.sUnitSize + GS!(5)) / 2;
// Just leave last digit visible
/*using (g.PushColor(0xFF595959))
@ -4166,7 +4304,7 @@ namespace IDE.ui
if ((drawLineNum < lineStart) || (drawLineNum >= lineEnd))
continue;
//hadLineIcon[drawLineNum - lineStart] = true;
g.Draw(DarkTheme.sDarkTheme.GetImage(.IconBookmark), Math.Max(GS!(-5), mEditWidget.mX - GS!(30)),
g.Draw(DarkTheme.sDarkTheme.GetImage(.IconBookmark), Math.Max(GS!(-5), mEditWidget.mX - GS!(30) - leftAdjust),
0 + bookmark.mLineNum * lineSpacing);
var curLineFlags = ref lineFlags[drawLineNum - lineStart];
@ -4199,6 +4337,10 @@ namespace IDE.ui
{
for (int lineIdx = lineStart; lineIdx < lineEnd; lineIdx++)
{
float drawHeight = ewc.mLineCoords[lineIdx + 1] - ewc.mLineCoords[lineIdx];
if (drawHeight < lineSpacing * 0.25f)
continue;
lineStr.Clear();
int maxLineChars = Int32.MaxValue;
@ -4216,7 +4358,43 @@ namespace IDE.ui
case 2: lineStr.AppendF("{0}", (lineIdx + 1) % 100);
default: lineStr.AppendF("{0}", lineIdx + 1);
}
g.DrawString(lineStr, 0, GS!(2) + lineIdx * lineSpacing, FontAlign.Right, editX - GS!(2));
g.DrawString(lineStr, 0, GS!(2) + ewc.mLineCoords[lineIdx], FontAlign.Right, editX - GS!(14));
}
}
}
for (int lineIdx = lineStart; lineIdx < lineEnd; lineIdx++)
{
int collapseLookup = lineIdx - mCollapseRegionView.mLineStart;
if ((collapseLookup >= 0) && (collapseLookup < mCollapseRegionView.mCollapseIndices.Count))
{
float drawHeight = ewc.mLineCoords[lineIdx + 1] - ewc.mLineCoords[lineIdx];
if (drawHeight < lineSpacing * 0.25f)
continue;
float boxAdjustTop = Math.Floor((lineSpacing - DarkTheme.sUnitSize)/2);
float boxAdjustBot = Math.Ceiling((lineSpacing - DarkTheme.sUnitSize)/2);
uint32 collapseIdx = mCollapseRegionView.mCollapseIndices[lineIdx - mCollapseRegionView.mLineStart];
if ((collapseIdx & CollapseRegionView.cStartFlag) != 0)
{
var entry = ewc.mOrderedCollapseEntries[collapseIdx & CollapseRegionView.cIdMask];
g.Draw(DarkTheme.sDarkTheme.GetImage(entry.mIsOpen ? .CollapseOpened : .CollapseClosed), editX - GS!(16), ewc.mLineCoords[lineIdx] + boxAdjustTop + GS!(2));
}
else if ((collapseIdx & CollapseRegionView.cEndFlag) != 0)
{
using (g.PushColor(0xFFA5A5A5))
{
g.FillRect(editX - (int)GS!(7.5f), ewc.mLineCoords[lineIdx] - (int)GS!(0.5f), (int)GS!(1.5f), lineSpacing);
g.FillRect(editX - (int)GS!(7.5f), ewc.mLineCoords[lineIdx] + lineSpacing - (int)GS!(1.5f), GS!(5), (int)GS!(1.5f));
}
}
else if (collapseIdx != 0)
{
using (g.PushColor(0xFFA5A5A5))
{
g.FillRect(editX - (int)GS!(7.5f), ewc.mLineCoords[lineIdx] - boxAdjustBot - GS!(5), (int)GS!(1.5f), lineSpacing + boxAdjustBot + boxAdjustTop + (int)GS!(12f));
}
}
}
}
@ -5255,6 +5433,11 @@ namespace IDE.ui
Point mousePos;
bool mouseoverFired = DarkTooltipManager.CheckMouseover(editWidgetContent, 10, out mousePos);
if (mouseoverFired)
{
}
#unwarn
CompilerBase compiler = ResolveCompiler;
@ -5571,6 +5754,8 @@ namespace IDE.ui
if (checkIdx >= mDeferredResolveResults.Count)
break;
resolveResult = mDeferredResolveResults[checkIdx];
}
if ((autocompleteOnly) && (resolveResult.mResolveType != .Autocomplete))
{
checkIdx++;
@ -5588,8 +5773,9 @@ namespace IDE.ui
checkIdx++;
continue;
}
using (mMonitor.Enter())
mDeferredResolveResults.RemoveAt(checkIdx);
}
//Debug.WriteLine($"HandleResolveResult {resolveResult}");
@ -6127,8 +6313,6 @@ namespace IDE.ui
DeleteAndNullify!(mQueuedAutoComplete);
}
ProcessDeferredResolveResults(0);
if (mLockFlashPct != 0)
{
mLockFlashPct += 0.02f;
@ -6139,6 +6323,20 @@ namespace IDE.ui
if ((mEmitRevision >= 0) && ((mUpdateCnt % 30) == 0))
CheckEmitRevision();
var ewc = (SourceEditWidgetContent)mEditWidget.Content;
using (mMonitor.Enter())
{
if (mQueuedCollapseData != null)
ewc.ParseCollapseRegions(mQueuedCollapseData.mData, mQueuedCollapseData.mTextVersion, ref mQueuedCollapseData.mCharIdSpan);
DeleteAndNullify!(mQueuedCollapseData);
}
if (ewc.mCollapseNeedsUpdate)
ewc.UpdateCollapse();
// Process after mQueuedCollapseData so mCharIdSpan is still valid
ProcessDeferredResolveResults(0);
}
void InjectErrors(BfPassInstance processingPassInstance, EditWidgetContent.CharData[] processResolveCharData, IdSpan processCharIdSpan, bool keepPersistentErrors)
@ -6267,7 +6465,7 @@ namespace IDE.ui
var font = IDEApp.sApp.mTinyCodeFont;
float lineWidth = Math.Max(font.GetWidth(ToStackString!(mEditWidget.Content.GetLineCount())) + GS!(8), GS!(32));
float lineWidth = Math.Max(font.GetWidth(ToStackString!(mEditWidget.Content.GetLineCount())) + GS!(24), GS!(32));
return Math.Max(GS!(24), lineWidth);
}
@ -6285,7 +6483,7 @@ namespace IDE.ui
}
// Always leave enough to read the first 3 lines
if (mHeight < GS!(88))
if ((mHeight < GS!(88)) && (mSplitBottomPanel == null))
mHeight = GS!(88);
float splitterHeight = GS!(3);
@ -6367,6 +6565,30 @@ namespace IDE.ui
{
base.MouseDown(x, y, btn, btnCount);
var ewc = (SourceEditWidgetContent)mEditWidget.Content;
if ((btn == 0) && (x >= mEditWidget.mX - GS!(13)) && (x < mEditWidget.mX - GS!(0)))
{
int lineClick = GetLineAt(0, y);
if (lineClick >= mCollapseRegionView.mLineStart)
{
int relLine = lineClick - mCollapseRegionView.mLineStart;
if (relLine < mCollapseRegionView.mCollapseIndices.Count)
{
uint32 collapseVal = mCollapseRegionView.mCollapseIndices[relLine];
if ((((collapseVal & CollapseRegionView.cStartFlag) != 0) && (btnCount == 1)) ||
(btnCount > 1))
{
int collapseIndex = collapseVal & CollapseRegionView.cIdMask;
var entry = ewc.mOrderedCollapseEntries[collapseIndex];
ewc.SetCollapseOpen(collapseIndex, !entry.mIsOpen);
}
return;
}
}
}
if (mSplitBottomPanel != null)
{
return;
@ -6438,12 +6660,15 @@ namespace IDE.ui
if (x > mEditWidget.mX - GS!(4))
return -1;
DarkEditWidgetContent darkEditWidgetContent = (DarkEditWidgetContent)mEditWidget.Content;
float lineSpacing = darkEditWidgetContent.mFont.GetLineSpacing();
var ewc = (SourceEditWidgetContent)mEditWidget.Content;
float relY = y - mEditWidget.mY - mEditWidget.Content.Y - GS!(3);
if (relY < 0)
return -1;
return (int)(relY / lineSpacing);
int resultIdx = ewc.mLineCoords.BinarySearch(relY);
if (resultIdx < 0)
return ~resultIdx - 1;
return resultIdx;
}
public bool SelectBreakpointsAtLine(int selectLine)
@ -6481,7 +6706,7 @@ namespace IDE.ui
if (btn == 0)
{
if ((x >= GS!(3)) && (x < mEditWidget.mX - GS!(8)))
if ((x >= GS!(3)) && (x < mEditWidget.mX - GS!(14)))
{
int lineClick = GetLineAt(x, y);
if (lineClick >= 0)
@ -6503,6 +6728,18 @@ namespace IDE.ui
}
}
public override void MouseLeave()
{
base.MouseLeave();
mMousePos = null;
}
public override void MouseMove(float x, float y)
{
base.MouseMove(x, y);
mMousePos = .(x, y);
}
public override void DrawAll(Graphics g)
{
DarkEditWidgetContent darkEditWidgetContent = (DarkEditWidgetContent)mEditWidget.Content;
@ -6623,5 +6860,6 @@ namespace IDE.ui
}
}
}
}
}

View file

@ -9151,6 +9151,272 @@ BF_EXPORT bool BF_CALLTYPE BfCompiler_ClassifySource(BfCompiler* bfCompiler, BfP
return !canceled;
}
BF_EXPORT const char* BF_CALLTYPE BfCompiler_GetCollapseRegions(BfCompiler* bfCompiler, BfParser* bfParser)
{
String& outString = *gTLStrReturn.Get();
outString.Clear();
class CollapseVisitor : public BfElementVisitor
{
public:
BfParser* mParser;
String& mOutString;
HashSet<int> mStartsFound;
char mSeriesKind;
int mStartSeriesIdx;
int mEndSeriesIdx;
public:
CollapseVisitor(BfParser* parser, String& string) : mOutString(string)
{
mParser = parser;
mSeriesKind = 0;
mStartSeriesIdx = -1;
mEndSeriesIdx = -1;
}
void UpdateSeries(BfAstNode* node, char kind)
{
if (mStartSeriesIdx != -1)
{
if ((node->mTriviaStart != mEndSeriesIdx + 1) || (kind != mSeriesKind))
{
// Flush
ConditionalAdd(mStartSeriesIdx, mStartSeriesIdx, mEndSeriesIdx, mSeriesKind);
mStartSeriesIdx = node->mSrcStart;
}
}
else
mStartSeriesIdx = node->mSrcStart;
mSeriesKind = kind;
mEndSeriesIdx = node->mSrcEnd - 1;
}
void FlushSeries()
{
if (mStartSeriesIdx != -1)
ConditionalAdd(mStartSeriesIdx, mStartSeriesIdx, mEndSeriesIdx, mSeriesKind);
mStartSeriesIdx = -1;
}
void ConditionalAdd(int anchor, int start, int end, char kind = '?')
{
bool isMultiline = false;
for (int i = start; i < end; i++)
{
if (mParser->mSrc[i] == '\n')
{
isMultiline = true;
break;
}
}
if (!isMultiline)
return;
char str[1024];
sprintf(str, "%c%d,%d,%d\n", kind, anchor, start, end);
mOutString.Append(str);
}
void Add(BfAstNode* anchor, BfAstNode* start, BfAstNode* end, char kind = '?')
{
if ((anchor == NULL) || (start == NULL) || (end == NULL))
return;
if (!mStartsFound.Add(start->mSrcStart))
return;
char str[1024];
sprintf(str, "%c%d,%d,%d\n", kind, anchor->mSrcStart, start->mSrcStart, end->mSrcStart);
mOutString.Append(str);
}
void Add(BfAstNode* anchor, BfAstNode* body, char kind = '?')
{
if (auto block = BfNodeDynCast<BfBlock>(body))
{
Add(anchor, block->mOpenBrace, block->mCloseBrace, kind);
}
}
virtual void Visit(BfMethodDeclaration* methodDeclaration) override
{
BfAstNode* anchorNode = methodDeclaration->mNameNode;
if (auto ctorDeclaration = BfNodeDynCast<BfConstructorDeclaration>(methodDeclaration))
anchorNode = ctorDeclaration->mThisToken;
if (auto dtorDeclaration = BfNodeDynCast<BfDestructorDeclaration>(methodDeclaration))
anchorNode = dtorDeclaration->mThisToken;
if (auto propertyDeclaration = BfNodeDynCast<BfOperatorDeclaration>(methodDeclaration))
anchorNode = propertyDeclaration->mOperatorToken;
Add(anchorNode, methodDeclaration->mBody, 'M');
BfElementVisitor::Visit(methodDeclaration);
}
virtual void Visit(BfNamespaceDeclaration* namespaceDeclaration) override
{
Add(namespaceDeclaration->mNamespaceNode, namespaceDeclaration->mBlock, 'N');
BfElementVisitor::Visit(namespaceDeclaration);
}
virtual void Visit(BfUsingDirective* usingDirective) override
{
UpdateSeries(usingDirective, 'U');
BfElementVisitor::Visit(usingDirective);
}
virtual void Visit(BfTypeDeclaration* typeDeclaration) override
{
BfAstNode* anchor = typeDeclaration->mNameNode;
if (anchor == NULL)
anchor = typeDeclaration->mStaticSpecifier;
Add(anchor, typeDeclaration->mDefineNode, 'T');
BfElementVisitor::Visit(typeDeclaration);
}
virtual void Visit(BfPropertyDeclaration* properyDeclaration) override
{
Add(properyDeclaration->mNameNode, properyDeclaration->mDefinitionBlock, 'P');
BfElementVisitor::Visit(properyDeclaration);
}
virtual void Visit(BfIndexerDeclaration* indexerDeclaration) override
{
Add(indexerDeclaration->mThisToken, indexerDeclaration->mDefinitionBlock, 'P');
BfElementVisitor::Visit(indexerDeclaration);
}
virtual void Visit(BfPropertyMethodDeclaration* methodDeclaration) override
{
Add(methodDeclaration->mNameNode, methodDeclaration->mBody);
BfElementVisitor::Visit(methodDeclaration);
}
virtual void Visit(BfIfStatement* ifStatement) override
{
Add(ifStatement->mIfToken, ifStatement->mTrueStatement);
Add(ifStatement->mElseToken, ifStatement->mFalseStatement);
BfElementVisitor::Visit(ifStatement);
}
virtual void Visit(BfRepeatStatement* repeatStatement) override
{
Add(repeatStatement->mRepeatToken, repeatStatement->mEmbeddedStatement);
BfElementVisitor::Visit(repeatStatement);
}
virtual void Visit(BfDoStatement* doStatement) override
{
Add(doStatement->mDoToken, doStatement->mEmbeddedStatement);
BfElementVisitor::Visit(doStatement);
}
virtual void Visit(BfForStatement* forStatement) override
{
Add(forStatement->mForToken, forStatement->mEmbeddedStatement);
BfElementVisitor::Visit(forStatement);
}
virtual void Visit(BfForEachStatement* forStatement) override
{
Add(forStatement->mForToken, forStatement->mEmbeddedStatement);
BfElementVisitor::Visit(forStatement);
}
virtual void Visit(BfUsingStatement* usingStatement) override
{
Add(usingStatement->mUsingToken, usingStatement->mEmbeddedStatement);
BfElementVisitor::Visit(usingStatement);
}
virtual void Visit(BfSwitchStatement* switchStatement) override
{
Add(switchStatement->mSwitchToken, switchStatement->mOpenBrace, switchStatement->mCloseBrace);
BfElementVisitor::Visit(switchStatement);
}
virtual void Visit(BfLambdaBindExpression* lambdaExpression) override
{
Add(lambdaExpression->mFatArrowToken, lambdaExpression->mBody);
BfElementVisitor::Visit(lambdaExpression);
}
virtual void Visit(BfBlock* block) override
{
Add(block->mOpenBrace, block->mOpenBrace, block->mCloseBrace);
BfElementVisitor::Visit(block);
}
};
CollapseVisitor collapseVisitor(bfParser, outString);
collapseVisitor.VisitChild(bfParser->mRootNode);
BfAstNode* regionStart = NULL;
BfPreprocessorNode* prevPreprocessorNode = NULL;
int ignoredSectionStart = -1;
for (auto element : bfParser->mSidechannelRootNode->mChildArr)
{
if (auto preprocessorNode = BfNodeDynCast<BfPreprocessorNode>(element))
{
if ((ignoredSectionStart != -1) && (prevPreprocessorNode != NULL) && (prevPreprocessorNode->mCommand != NULL))
{
collapseVisitor.ConditionalAdd(prevPreprocessorNode->mCommand->mSrcStart, ignoredSectionStart, preprocessorNode->mSrcEnd - 1);
ignoredSectionStart = -1;
}
StringView sv = preprocessorNode->mCommand->ToStringView();
if (sv == "region")
regionStart = preprocessorNode->mCommand;
else if (sv == "endregion")
{
collapseVisitor.Add(regionStart, regionStart, preprocessorNode->mCommand, 'R');
regionStart = NULL;
}
prevPreprocessorNode = preprocessorNode;
}
if (auto preprocessorNode = BfNodeDynCast<BfPreprocesorIgnoredSectionNode>(element))
{
if (ignoredSectionStart == -1)
{
for (int i = preprocessorNode->mSrcStart; i < preprocessorNode->mSrcEnd - 1; i++)
{
if (bfParser->mSrc[i] == '\n')
{
ignoredSectionStart = i + 1;
break;
}
}
}
}
char kind = 0;
if (auto commentNode = BfNodeDynCast<BfCommentNode>(element))
collapseVisitor.UpdateSeries(commentNode, 'C');
}
collapseVisitor.FlushSeries();
return outString.c_str();
}
BF_EXPORT bool BF_CALLTYPE BfCompiler_VerifyTypeName(BfCompiler* bfCompiler, char* name, int cursorPos)
{
String typeName = name;