1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-07-02 14:25:59 +02:00

Initial checkin

This commit is contained in:
Brian Fiete 2019-08-23 11:56:54 -07:00
parent c74712dad9
commit 078564ac9e
3242 changed files with 1616395 additions and 0 deletions

127
IDE/src/BeefConfig.bf Normal file
View file

@ -0,0 +1,127 @@
using IDE.Util;
using System;
using System.Collections.Generic;
using System.IO;
using Beefy.utils;
namespace IDE
{
class BeefConfig
{
public class RegistryEntry
{
public String mProjName ~ delete _;
public SemVer mVersion ~ delete _;
public VerSpecRecord mLocation ~ delete _;
public ConfigFile mConfigFile;
}
public class LibDirectory
{
public String mPath ~ delete _;
public ConfigFile mConfigFile;
}
public class ConfigFile
{
public String mFilePath ~ delete _;
public String mConfigDir ~ delete _;
}
List<ConfigFile> mConfigFiles = new List<ConfigFile>() ~ DeleteContainerAndItems!(_);
public List<RegistryEntry> mRegistry = new List<RegistryEntry>() ~ DeleteContainerAndItems!(_);
List<String> mConfigPathQueue = new List<String>() ~ DeleteContainerAndItems!(_);
List<LibDirectory> mLibDirectories = new List<LibDirectory>() ~ DeleteContainerAndItems!(_);
Result<void> Load(StringView path)
{
let data = scope StructuredData();
if (data.Load(path) case .Err)
return .Err;
let configFile = new ConfigFile();
configFile.mFilePath = new String(path);
configFile.mConfigDir = new String();
Path.GetDirectoryPath(configFile.mFilePath, configFile.mConfigDir);
for (let projName in data.Enumerate("Registry"))
{
RegistryEntry regEntry = new RegistryEntry();
regEntry.mProjName = new String(projName);
mRegistry.Add(regEntry);
regEntry.mConfigFile = configFile;
var verString = scope String();
data.GetString("Version", verString);
regEntry.mVersion = new SemVer();
regEntry.mVersion.Parse(verString).IgnoreError();
regEntry.mLocation = new VerSpecRecord();
using (data.Open("Location"))
regEntry.mLocation.Parse(data).IgnoreError();
}
for (data.Enumerate("LibDirs"))
{
String dirStr = scope .();
data.GetCurString(dirStr);
if (!dirStr.IsWhiteSpace)
{
LibDirectory libDir = new .();
libDir.mPath = new String(dirStr);
libDir.mConfigFile = configFile;
mLibDirectories.Add(libDir);
}
}
mConfigFiles.Add(configFile);
return .Ok;
}
public void QueuePaths(StringView topLevelDir)
{
let dir = scope String(topLevelDir);
if (!dir.EndsWith(IDEUtils.cNativeSlash))
dir.Append(IDEUtils.cNativeSlash);
while (true)
{
let path = scope String(dir);
path.Append("BeefConfig.toml");
if (File.Exists(path))
{
if (mConfigPathQueue.Contains(path))
break; // We have this and everthing under it already
mConfigPathQueue.Add(new String(path));
}
// We had logic to check parent directories, but this seems unsound. Revisit this decision when we have
// better usage cases in mind.
break;
/*if (dir.Length < 2)
break;
int slashPos = dir.LastIndexOf(IDEUtils.cNativeSlash, dir.Length - 2);
if (slashPos == -1)
break;
dir.RemoveToEnd(slashPos + 1);*/
}
}
public Result<void> Load()
{
for (int i = mConfigPathQueue.Count - 1; i >= 0; i--)
{
let path = mConfigPathQueue[i];
Try!(Load(path));
}
return .Ok;
}
}
}

109
IDE/src/Board.bf Normal file
View file

@ -0,0 +1,109 @@
#if false
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Beefy;
using Beefy.gfx;
using Beefy.widgets;
using Beefy.theme;
using Beefy.theme.dark;
namespace IDE
{
public class Board : Widget
{
Image mImage;
Image mSegment;
Font mFont;
float mMouseX;
float mMouseY;
ButtonWidget mButton;
EditWidget mEditWidget;
public Board()
{
mImage = Image.LoadFromFile(BFApp.sApp.mInstallDir + "images/tgaTest.tga");
mSegment = mImage.CreateImageSegment(20, 20, 40, 40);
mFont = Font.LoadFromFile(BFApp.sApp.mInstallDir + "fonts/SegoeUI8.fnt");
mButton = ThemeFactory.mDefault.CreateButton(this, "Test", 50, 50, 200, 30);
ThemeFactory.mDefault.CreateCheckbox(this, 50, 100, 20, 20);
/*mEditWidget = ThemeFactory.mDefault.CreateEditWidget(this, 50, 90, 200, 30);
mEditWidget.SetText("Hi");*/
mEditWidget = ThemeFactory.mDefault.CreateEditWidget(this, 50, 90, 500, 480);
mEditWidget.InitScrollbars(true, true);
mEditWidget.Content.mIsMultiline = true;
mEditWidget.Content.mWordWrap = false;
mEditWidget.SetText("Hi");
/*mEditWidget = ThemeFactory.mDefault.CreateEditWidget(this, 50, 90, 200, 20);
mEditWidget.Content.mMultiline = false;
mEditWidget.Content.mWordWrap = false;
mEditWidget.SetText("Hi");*/
}
public override void MouseMove(float x, float y)
{
base.MouseMove(x, y);
mMouseX = x;
mMouseY = y;
}
public override void MouseLeave()
{
base.MouseLeave();
mMouseX = -100;
mMouseY = -100;
}
public override void Draw(Graphics g)
{
base.Draw(g);
g.SetFont(mFont);
using (g.PushColor(DarkTheme.COLOR_BKG))
g.FillRect(0, 0, mWidth, mHeight);
using (g.PushColor(Color.Black))
g.FillRect(0, 60, 500, 60);
//g.mColor = 0xFF000000;
g.mColor = 0xFFFFFFFF;
//g.mColor = 0xD080F080;
//g.Draw(mSegment, 0, 0);
Matrix matrix = Matrix.IdentityMatrix;
matrix.Rotate(0.2f);
using (g.PushColor(Color.Black))
g.DrawString(String.Format("{0} This is a test of the font system, pretty cool!", mUpdateCnt), 30, 300);
g.mFont = mFont;
using (g.PushMatrix(ref matrix))
g.DrawString("This is a test of the font system, pretty cool!\nI think!", 30, 62);
using (g.PushColor(0xFFFF0000))
g.FillRect(mMouseX - 1, mMouseY - 1, 3, 3);
g.FillRectGradient(20, 20, 40, 40, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFFFFFFFF);
//g.Draw(mTexture, 20 * (mCount % 3), 20);
//++mCount;
}
}
}
#endif

126
IDE/src/BookmarkManager.bf Normal file
View file

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using IDE.ui;
using System.Diagnostics;
namespace IDE
{
public class TrackedTextElement
{
public int mRefCount = 1;
public bool mIsDead;
public String mFileName ~ delete _;
public int32 mLineNum;
public int32 mColumn;
public bool mSnapToLineStart = true;
public int32 mMoveIdx; // Increments when we manually move an element (ie: a history location updating because the user types near the previous history location)
public virtual void Move(int wantLineNum, int wantColumn)
{
mLineNum = (int32)wantLineNum;
mColumn = (int32)wantColumn;
}
public virtual void Kill()
{
mIsDead = true;
Deref();
}
public void AddRef()
{
mRefCount++;
}
public void Deref()
{
if (--mRefCount == 0)
delete this;
}
public ~this()
{
Debug.Assert(mRefCount == 0);
}
}
public class Bookmark : TrackedTextElement
{
public String mNotes ~ delete _;
}
public class BookmarkManager
{
public List<Bookmark> mBookmarkList = new List<Bookmark>() ~
{
for (var bookmark in mBookmarkList)
bookmark.Kill();
delete _;
};
public int32 mBookmarkIdx;
public Bookmark CreateBookmark(String fileName, int wantLineNum, int wantColumn)
{
mBookmarkIdx = (int32)mBookmarkList.Count;
Bookmark bookmark = new Bookmark();
bookmark.mFileName = new String(fileName);
bookmark.mLineNum = (int32)wantLineNum;
bookmark.mColumn = (int32)wantColumn;
mBookmarkList.Add(bookmark);
gApp.mDebugger.mBreakpointsChangedDelegate();
return bookmark;
}
public void DeleteBookmark(Bookmark bookmark)
{
int idx = mBookmarkList.IndexOf(bookmark);
mBookmarkList.RemoveAt(idx);
if (mBookmarkIdx == idx)
mBookmarkIdx--;
if (mBookmarkIdx >= mBookmarkList.Count)
mBookmarkIdx = (int32)mBookmarkList.Count - 1;
gApp.mDebugger.mBreakpointsChangedDelegate();
bookmark.Kill();
}
public void Clear()
{
for (var bookmark in mBookmarkList)
bookmark.Kill();
mBookmarkList.Clear();
mBookmarkIdx = 0;
gApp.mDebugger.mBreakpointsChangedDelegate();
}
public void PrevBookmark()
{
if (mBookmarkList.Count == 0)
return;
mBookmarkIdx--;
if (mBookmarkIdx < 0)
mBookmarkIdx = (int32)mBookmarkList.Count - 1;
var bookmark = mBookmarkList[mBookmarkIdx];
gApp.ShowSourceFileLocation(bookmark.mFileName, -1, -1, bookmark.mLineNum, bookmark.mColumn, LocatorType.Smart);
}
public void NextBookmark()
{
if (mBookmarkList.Count == 0)
return;
mBookmarkIdx++;
if (mBookmarkIdx >= mBookmarkList.Count)
mBookmarkIdx = 0;
var bookmark = mBookmarkList[mBookmarkIdx];
gApp.ShowSourceFileLocation(bookmark.mFileName, -1, -1, bookmark.mLineNum, bookmark.mColumn, LocatorType.Smart);
}
}
}

132
IDE/src/BuildOptions.bf Normal file
View file

@ -0,0 +1,132 @@
using System;
using Beefy.utils;
namespace IDE
{
class BuildOptions
{
public enum LTOType
{
None,
Thin,
}
public enum EmitDebugInfo
{
No,
Yes,
LinesOnly,
}
public enum SIMDSetting
{
None,
MMX,
SSE,
SSE2,
SSE3,
SSE4,
SSE41,
AVX,
AVX2,
}
public enum BfOptimizationLevel
{
case O0;
case O1;
case O2;
case O3;
case Og;
case OgPlus;
public bool IsOptimized()
{
return (this != .Og) && (this != .OgPlus) && (this != .O0);
}
}
}
public class DistinctBuildOptions
{
public enum CreateState
{
Normal,
New,
Deleted
}
public CreateState mCreateState;
[Reflect]
public String mFilter = new String() ~ delete _;
[Reflect]
public BuildOptions.SIMDSetting? mBfSIMDSetting;
[Reflect]
public BuildOptions.BfOptimizationLevel? mBfOptimizationLevel;
[Reflect]
public BuildOptions.EmitDebugInfo? mEmitDebugInfo;
[Reflect]
public bool? mRuntimeChecks;
[Reflect]
public bool? mInitLocalVariables;
[Reflect]
public bool? mEmitDynamicCastCheck;
[Reflect]
public bool? mEmitObjectAccessCheck; // Only valid with mObjectHasDebugFlags
[Reflect]
public int32? mAllocStackTraceDepth;
public ~this()
{
}
public DistinctBuildOptions Duplicate()
{
var newVal = new DistinctBuildOptions();
newVal.mFilter.Set(mFilter);
newVal.mBfSIMDSetting = mBfSIMDSetting;
newVal.mBfOptimizationLevel = mBfOptimizationLevel;
newVal.mEmitDebugInfo = mEmitDebugInfo;
newVal.mRuntimeChecks = mRuntimeChecks;
newVal.mInitLocalVariables = mInitLocalVariables;
newVal.mEmitDynamicCastCheck = mEmitDynamicCastCheck;
newVal.mEmitObjectAccessCheck = mEmitObjectAccessCheck;
newVal.mAllocStackTraceDepth = mAllocStackTraceDepth;
return newVal;
}
public void Deserialize(StructuredData data)
{
data.GetString("Filter", mFilter);
if (data.Contains("BfSIMDSetting"))
mBfSIMDSetting = data.GetEnum<BuildOptions.SIMDSetting>("BfSIMDSetting");
if (data.Contains("BfOptimizationLevel"))
mBfOptimizationLevel = data.GetEnum<BuildOptions.BfOptimizationLevel>("BfOptimizationLevel");
if (data.Contains("EmitDebugInfo"))
mEmitDebugInfo = data.GetEnum<BuildOptions.EmitDebugInfo>("EmitDebugInfo");
if (data.Contains("RuntimeChecks"))
mRuntimeChecks = data.GetBool("RuntimeChecks");
if (data.Contains("InitLocalVariables"))
mInitLocalVariables = data.GetBool("InitLocalVariables");
if (data.Contains("EmitDynamicCastCheck"))
mEmitDynamicCastCheck = data.GetBool("EmitDynamicCastCheck");
if (data.Contains("EmitObjectAccessCheck"))
mEmitObjectAccessCheck = data.GetBool("EmitObjectAccessCheck");
if (data.Contains("AllocStackTraceDepth"))
mAllocStackTraceDepth = data.GetInt("AllocStackTraceDepth");
}
public void Serialize(StructuredData data)
{
data.Add("Filter", mFilter);
data.ConditionalAdd("BfSIMDSetting", mBfSIMDSetting);
data.ConditionalAdd("BfOptimizationLevel", mBfOptimizationLevel);
data.ConditionalAdd("EmitDebugInfo", mEmitDebugInfo);
data.ConditionalAdd("RuntimeChecks", mRuntimeChecks);
data.ConditionalAdd("InitLocalVariables", mInitLocalVariables);
data.ConditionalAdd("EmitDynamicCastCheck", mEmitDynamicCastCheck);
data.ConditionalAdd("EmitObjectAccessCheck", mEmitObjectAccessCheck);
data.ConditionalAdd("AllocStackTraceDepth", mAllocStackTraceDepth);
}
}
}

View file

@ -0,0 +1,768 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using Beefy.widgets;
using Beefy.utils;
using IDE.Compiler;
using Beefy;
#if IDE_C_SUPPORT
namespace IDE.Clang
{
public class ClangCompiler : CompilerBase
{
public const bool cEnableClangHelper = false;
public enum CompilerType
{
Resolve,
Build
}
public enum DepCheckerType
{
CDep, // Fast - custom in-memory checker
Clang // Accurate - .dep files written after build
}
public class FileEntry
{
public ProjectSource mProjectSource;
public String mFilePath ~ delete _;
public List<String> mClangFileRefs ~ DeleteContainerAndItems!(_);
public List<String> mCDepFileRefs ~ DeleteContainerAndItems!(_);
public String mObjectFilePath ~ delete _;
public String mBuildStringFilePath ~ delete _;
}
public class CacheEntry
{
public List<String> mFileRefs = new List<String>();
}
[StdCall, CLink]
static extern void* ClangHelper_Create(bool isForResolve);
[StdCall, CLink]
static extern void ClangHelper_Delete(void* clangHelper);
[StdCall, CLink]
static extern void ClangHelper_AddTranslationUnit(void* clangHelper, char8* fileName, char8* headerPrefix, char8* clangArgs, void* elementTypeArray, int32 char8Len);
[StdCall, CLink]
static extern void ClangHelper_RemoveTranslationUnit(void* clangHelper, char8* fileName);
[StdCall, CLink]
static extern char8* ClangHelper_Classify(void* clangHelper, char8* fileName, void* elementTypeArray, int32 char8Len, int32 cursorIdx, int32 errorLookupTextIdx,bool ignoreErrors);
[StdCall, CLink]
static extern char8* ClangHelper_Autocomplete(void* clangHelper, char8* fileName, void* elementTypeArray, int32 char8Len, int32 cursorIdx);
[StdCall, CLink]
static extern char8* ClangHelper_FindDefinition(void* clangHelper, char8* fileName, int32 defPos, out int32 outDefLine, out int32 outDefColumn);
[StdCall, CLink]
static extern char8* ClangHelper_GetNavigationData(void* clangHelper, char8* fileName);
[StdCall, CLink]
static extern char8* ClangHelper_GetCurrentLocation(void* clangHelper, char8* fileName, int32 defPos);
[StdCall, CLink]
static extern char8* ClangHelper_DetermineFilesReferenced(void* clangHelper, char8* fileName);
[StdCall, CLink]
static extern void CDep_ClearCache();
[StdCall, CLink]
static extern void CDep_Shutdown();
[StdCall, CLink]
static extern char8* CDep_DetermineFilesReferenced(char8* fileName, String cArgs);
[StdCall, CLink]
static extern int32 CDep_GetIncludePosition(char8* sourceFileName, char8* sourceContent, char8* headerFileName, String cArgs);
//static int sRefCount = 0;
void* mNativeClangHelper;
public List<ProjectSource> mSourceMRUList = new List<ProjectSource>() ~ delete _;
public int32 mProjectSourceVersion; // Updated when MRU list changes, or when a CPP is saved
public Dictionary<ProjectSource, FileEntry> mProjectFileSet = new Dictionary<ProjectSource, FileEntry>() ~ delete _;
public Dictionary<Project, String> mProjectBuildString = new Dictionary<Project, String>() ~ { for (var val in _.Values) delete val; delete _; }; // Don't delete 'Project', only the String
public Dictionary<String, String> mHeaderToSourceMap = new Dictionary<String, String>() ~ DeleteDictionyAndKeysAndItems!(_);
FileWatcher mFileWatcher = new FileWatcher() ~ delete _;
public bool mDoDependencyCheck = true;
public ClangCompiler mPairedCompiler;
public bool mCompileWaitsForQueueEmpty = true;
CompilerType mCompilerType;
protected class ClangProjectSourceCommand : Command
{
public ProjectSource mProjectSource;
}
protected class ClangCheckDependencyCommand : Command
{
public ProjectSource mProjectSource;
public DepCheckerType mDepCheckerType;
}
protected class ClangReparseSourceCommand : Command
{
public ProjectSource mProjectSource;
}
protected class FileRemovedCommand : Command
{
public String mFileName ~ delete _;
}
public this(bool isForResolve)
{
mCompilerType = isForResolve ? CompilerType.Resolve : CompilerType.Build;
//if (sRefCount == 0)
if (cEnableClangHelper)
mNativeClangHelper = ClangHelper_Create(isForResolve);
//sRefCount++;
}
public ~this()
{
CancelBackground();
//--sRefCount;
//if (sRefCount == 0)
{
ClangHelper_Delete(mNativeClangHelper);
mNativeClangHelper = null;
}
CDep_Shutdown();
for (var fileEntry in mProjectFileSet.Values)
delete fileEntry;
}
public void UpdateMRU(ProjectSource projectSource)
{
if (IDEUtils.IsHeaderFile(projectSource.mPath))
return;
using (mMonitor.Enter())
{
if ((mSourceMRUList.Count > 0) && (mSourceMRUList[mSourceMRUList.Count - 1] == projectSource))
return;
mProjectSourceVersion++;
mSourceMRUList.Remove(projectSource);
mSourceMRUList.Add(projectSource);
while (mSourceMRUList.Count > 10)
mSourceMRUList.RemoveAt(0);
}
}
public void QueueFileRemoved(String filePath)
{
FileRemovedCommand command = new FileRemovedCommand();
command.mFileName = new String(filePath);
QueueCommand(command);
}
public override void QueueProjectSource(ProjectSource projectSource)
{
using (mMonitor.Enter())
{
for (var command in mCommandQueue)
{
var checkProjectSourceCommand = command as ClangProjectSourceCommand;
if ((checkProjectSourceCommand != null) && (checkProjectSourceCommand.mProjectSource == projectSource))
return;
}
ClangProjectSourceCommand clangProjectSourceCommand = new ClangProjectSourceCommand();
clangProjectSourceCommand.mProjectSource = projectSource;
QueueCommand(clangProjectSourceCommand);
}
}
public void QueueCheckDependencies(ProjectSource projectSource, DepCheckerType depType)
{
for (var command in mCommandQueue)
{
var checkCheckDependencyCommand = command as ClangCheckDependencyCommand;
if ((checkCheckDependencyCommand != null) && (checkCheckDependencyCommand.mProjectSource == projectSource) &&
(checkCheckDependencyCommand.mDepCheckerType == depType))
return;
}
ClangCheckDependencyCommand clangCheckDependencyCommand = new ClangCheckDependencyCommand();
clangCheckDependencyCommand.mProjectSource = projectSource;
QueueCommand(clangCheckDependencyCommand);
}
public bool Autocomplete(String fileName, EditWidgetContent.CharData[] char8Data, int textLength, int cursorIdx, String outResult)
{
EditWidgetContent.CharData* char8DataPtr = char8Data.CArray();
{
char8* returnStringPtr = ClangHelper_Autocomplete(mNativeClangHelper, fileName, char8DataPtr, (int32)textLength, (int32)cursorIdx);
if (returnStringPtr == null)
return false;
outResult.Append(returnStringPtr);
return true;
}
}
public bool Classify(String fileName, EditWidgetContent.CharData[] char8Data, int textLength, int cursorIdx, int errorLookupTextIdx, bool ignoreErrors, String outResult)
{
EditWidgetContent.CharData* char8DataPtr = char8Data.CArray();
{
char8* returnStringPtr = ClangHelper_Classify(mNativeClangHelper, fileName, char8DataPtr, (int32)textLength, (int32)cursorIdx, (int32)errorLookupTextIdx, ignoreErrors);
if (returnStringPtr == null)
return false;
outResult.Append(returnStringPtr);
return true;
}
}
public bool DetermineFilesReferenced(String fileName, String outResult)
{
char8* returnStringPtr = ClangHelper_DetermineFilesReferenced(mNativeClangHelper, fileName);
if (returnStringPtr == null)
return false;
outResult.Append(returnStringPtr);
return true;
}
public bool CDepDetermineFilesReferenced(String fileName, String cArgs, String outResult)
{
char8* returnStringPtr = CDep_DetermineFilesReferenced(fileName, cArgs);
if (returnStringPtr == null)
return false;
outResult.Append(returnStringPtr);
return true;
}
public int32 CDepGetIncludePosition(String sourceFileName, String sourceContent, String headerFileName, String cArgs)
{
return CDep_GetIncludePosition(sourceFileName, sourceContent, headerFileName, cArgs);
}
public bool FindDefinition(String fileName, int defPos, String defFileName, out int defLine, out int defColumn)
{
String useDefFileName = defFileName;
int32 defLineOut;
int32 defColumnOut;
char8* fileNamePtr = ClangHelper_FindDefinition(mNativeClangHelper, fileName, (int32)defPos, out defLineOut, out defColumnOut);
defLine = defLineOut;
defColumn = defColumnOut;
if (fileNamePtr == null)
{
useDefFileName = null;
defLine = 0;
defColumn = 0;
return false;
}
useDefFileName.Append(fileNamePtr);
return true;
}
public void GetNavigationData(String fileName, String outResult)
{
char8* strPtr = ClangHelper_GetNavigationData(mNativeClangHelper, fileName);
outResult.Append(strPtr);
}
public void GetCurrentLocation(String fileName, String outResult, int defPos)
{
char8* strPtr = ClangHelper_GetCurrentLocation(mNativeClangHelper, fileName, (int32)defPos);
outResult.Append(strPtr);
}
public void GetBuildStringFileName(String buildDir, Project project, String outBuildStr)
{
outBuildStr.Append(buildDir, "/", project.mProjectName, ".copt");
}
void CheckClangDependencies(ProjectSource projectSource)
{
String srcFilePath = scope String();
/*if (projectSource.mPath == "../../BeefRT/gperftools/src/stacktrace.cc")
{
NOP!();
}*/
using (projectSource.mProject.mMonitor.Enter())
projectSource.GetFullImportPath(srcFilePath);
FileEntry fileEntry;
mProjectFileSet.TryGetValue(projectSource, out fileEntry);
if (fileEntry == null)
{
fileEntry = new FileEntry();
using (mMonitor.Enter())
{
mProjectFileSet[projectSource] = fileEntry;
}
}
fileEntry.mProjectSource = projectSource;
String.NewOrSet!(fileEntry.mFilePath, srcFilePath);
List<String> oldFileRefs = fileEntry.mClangFileRefs;
List<String> newFileRefs = new List<String>();
String depFilePath = scope String();
IDEApp.sApp.GetClangOutputFilePathWithoutExtension(projectSource, depFilePath);
depFilePath.Append(".dep");
// We don't add the .dep since the dep could write after the obj
//newFileRefs.Add(new String(depFilePath));
var fileText = scope String();
var result = File.ReadAllText(depFilePath, fileText);
if (case .Ok = result)
{
// We
newFileRefs.Add(new String(srcFilePath));
int checkIdx = fileText.IndexOf("c:/beef/BeefRT/gc.cpp");
if (checkIdx != -1)
{
NOP!();
}
int32 textStart = -1;
for (int32 i = 0; i < fileText.Length; i++)
{
bool lineEnd = false;
char8 c = fileText[i];
if (c == ':')
{
if (fileText[i + 1] == ' ')
lineEnd = true;
}
else if (c == ' ')
{
if ((i > 0) && (fileText[i - 1] != '\\'))
{
lineEnd = true;
}
/*else if ((i < fileText.Length - 2) && (fileText[i + 1] == '\\') && ((fileText[i + 2] == '\n') || (fileText[i + 2] == '\r')))
{
lineEnd = true;
}*/
}
else if (Char8.IsWhiteSpace(c))
{
lineEnd = true;
}
else if (c != '\\')
{
if (textStart == -1)
textStart = i;
}
if ((lineEnd) && (textStart != -1))
{
if ((projectSource.mPath == "cpp/sys.cpp") && (newFileRefs.Count == 9))
{
NOP!();
}
String line = new String();
fileText.Substring(textStart, i - textStart, line);
textStart = -1;
line.Replace("\\ ", " ");
if (line.EndsWith(" \\"))
line.Remove(line.Length - 2);
IDEUtils.FixFilePath(line);
newFileRefs.Add(line);
}
}
}
for (var origRefFilePath in newFileRefs)
{
String refFilePath = scope String(origRefFilePath);
IDEUtils.FixFilePath(refFilePath);
bool found = false;
if (oldFileRefs != null)
{
int32 idx = oldFileRefs.IndexOf(refFilePath);
if (idx != -1)
{
found = true;
delete oldFileRefs[idx];
oldFileRefs.RemoveAtFast(idx);
}
}
if (!found)
{
// Don't watch for writes of compiler-generated files, otherwise we get changes triggered
// after every compile
bool ignoreWrites = refFilePath.EndsWith(".obj") || refFilePath.EndsWith(".dep");
mFileWatcher.WatchFile(refFilePath, projectSource, ignoreWrites);
mDoDependencyCheck = true;
}
}
fileEntry.mClangFileRefs = newFileRefs;
if (oldFileRefs != null)
{
for (var oldRef in oldFileRefs)
mFileWatcher.RemoveWatch(oldRef, projectSource);
DeleteContainerAndItems!(oldFileRefs);
}
}
void CheckCDepDependencies(ProjectSource projectSource, String clangArgs)
{
FileEntry fileEntry;
mProjectFileSet.TryGetValue(projectSource, out fileEntry);
if (fileEntry == null)
return; // Why is this null?
String srcFilePath = scope String();
projectSource.GetFullImportPath(srcFilePath);
String filesReferencedStr = scope String();
CDepDetermineFilesReferenced(srcFilePath, clangArgs, filesReferencedStr);
//Debug.Assert(filesReferencedStr != null);
if (fileEntry.mCDepFileRefs == null)
fileEntry.mCDepFileRefs = new List<String>();
else
{
for (var str in fileEntry.mCDepFileRefs)
delete str;
fileEntry.mCDepFileRefs.Clear();
}
var fileViews = scope List<StringView>();
filesReferencedStr.Split(fileViews, '\n');
for (var fileView in fileViews)
if (fileView.Length > 0)
fileEntry.mCDepFileRefs.Add(new String(fileView));
}
public void GetClangArgs(ProjectSource projectSource, String outClangArgs)
{
using (projectSource.mProject.mMonitor.Enter())
{
var clangArgList = new List<String>();
IDEApp.sApp.GetClangResolveArgs(projectSource.mProject, clangArgList);
if (clangArgList != null)
outClangArgs.JoinInto("\n", clangArgList.GetEnumerator());
DeleteContainerAndItems!(clangArgList);
}
}
public void AddTranslationUnit(ProjectSource projectSource, String headerPrefix)
{
String srcFilePath = scope String();
using (projectSource.mProject.mMonitor.Enter())
projectSource.GetFullImportPath(srcFilePath);
String clangArgs = scope String();
GetClangArgs(projectSource, clangArgs);
ClangHelper_AddTranslationUnit(mNativeClangHelper, srcFilePath, headerPrefix, clangArgs, null, 0);
}
public void AddTranslationUnit(ProjectSource projectSource, String headerPrefix, EditWidgetContent.CharData[] char8Data, int char8Len)
{
String srcFilePath = scope String();
using (projectSource.mProject.mMonitor.Enter())
projectSource.GetFullImportPath(srcFilePath);
String clangArgs = scope String();
GetClangArgs(projectSource, clangArgs);
EditWidgetContent.CharData* char8DataPtr = char8Data.CArray();
{
ClangHelper_AddTranslationUnit(mNativeClangHelper, srcFilePath, headerPrefix, clangArgs, char8DataPtr, (int32)char8Len);
}
}
public void AddTranslationUnit(String srcFilePath, String headerPrefix, String clangArgs)
{
ClangHelper_AddTranslationUnit(mNativeClangHelper, srcFilePath, headerPrefix, clangArgs, null, 0);
}
public static int32 sFileIdx = 0;
public static int32 sThreadRunningCount = 0;
protected override void DoProcessQueue()
{
// libclang CXIndices aren't current thread safe
sThreadRunningCount++;
Debug.Assert(sThreadRunningCount < 2);
while (mThreadYieldCount == 0)
{
Command command = null;
using (mMonitor.Enter())
{
if (mCommandQueue.Count == 0)
break;
command = mCommandQueue[0];
}
if (command is ClangProjectSourceCommand)
{
sFileIdx++;
var clangProjectSourceCommand = (ClangProjectSourceCommand)command;
/*if (clangProjectSourceCommand.mProjectSource.mPath == "../../BeefRT/gperftools/src/malloc_extension.cc")
{
NOP!();
}*/
var projectSource = clangProjectSourceCommand.mProjectSource;
String clangArgs = scope String();
GetClangArgs(projectSource, clangArgs);
String srcFilePath = scope String();
using (projectSource.mProject.mMonitor.Enter())
{
projectSource.GetFullImportPath(srcFilePath);
}
if (clangArgs == null)
{
// Don't actually do anything
}
else if (mCompilerType == CompilerType.Resolve)
{
ClangHelper_AddTranslationUnit(mNativeClangHelper, srcFilePath, null, clangArgs, null, 0);
}
else if (mCompilerType == CompilerType.Build)
{
if (!IDEUtils.IsHeaderFile(srcFilePath))
{
CheckClangDependencies(projectSource);
CheckCDepDependencies(projectSource, clangArgs);
}
else
{
}
}
}
if (command is ClangCheckDependencyCommand)
{
var clangCheckDependencyCommand = (ClangCheckDependencyCommand)command;
var projectSource = clangCheckDependencyCommand.mProjectSource;
if (clangCheckDependencyCommand.mDepCheckerType == DepCheckerType.Clang)
{
CheckClangDependencies(projectSource);
}
else
{
String clangArgs = scope String();
String srcFilePath = scope String();
using (projectSource.mProject.mMonitor.Enter())
{
projectSource.GetFullImportPath(srcFilePath);
List<String> clangArgList = new List<String>();
IDEApp.sApp.GetClangResolveArgs(projectSource.mProject, clangArgList);
if (clangArgList != null)
clangArgs.JoinInto("\n", clangArgList.GetEnumerator());
DeleteContainerAndItems!(clangArgList);
}
CheckCDepDependencies(projectSource, clangArgs);
}
}
if (command is FileRemovedCommand)
{
var fileRemovedCommand = (FileRemovedCommand)command;
ClangHelper_RemoveTranslationUnit(mNativeClangHelper, fileRemovedCommand.mFileName);
}
if (command is ProjectSourceRemovedCommand)
{
var fileRemovedCommand = (ProjectSourceRemovedCommand)command;
String srcFileName = scope String();
var projectSource = fileRemovedCommand.mProjectSource;
using (projectSource.mProject.mMonitor.Enter())
{
projectSource.GetFullImportPath(srcFileName);
}
ClangHelper_RemoveTranslationUnit(mNativeClangHelper, srcFileName);
using (this.mMonitor.Enter())
{
mHeaderToSourceMap.Remove(srcFileName);
}
var fileEntry = GetProjectEntry(projectSource);
if (fileEntry != null)
{
using (this.mMonitor.Enter())
{
mProjectFileSet.Remove(projectSource);
mSourceMRUList.Remove(projectSource);
}
for(var fileRef in fileEntry.mClangFileRefs)
mFileWatcher.RemoveWatch(fileRef, projectSource);
if (fileEntry.mObjectFilePath != null)
mFileWatcher.RemoveWatch(fileEntry.mObjectFilePath, null);
if (fileEntry.mBuildStringFilePath != null)
mFileWatcher.RemoveWatch(fileEntry.mBuildStringFilePath, null);
delete fileEntry;
}
}
using (this.mMonitor.Enter())
{
delete command;
if (!mShuttingDown)
{
var poppedCmd = mCommandQueue.PopFront();
Debug.Assert(poppedCmd == command);
}
}
}
if ((mCompilerType == CompilerType.Build) && (mCommandQueue.Count == 0))
{
// Clear out cache after we've finished parsing everything
CDep_ClearCache();
}
sThreadRunningCount--;
}
public bool HasProjectFile(ProjectSource projectSource)
{
using (this.mMonitor.Enter())
{
return mProjectFileSet.ContainsKey(projectSource);
}
}
public FileEntry GetProjectEntry(ProjectSource projectSource)
{
using (this.mMonitor.Enter())
{
FileEntry fileEntry;
mProjectFileSet.TryGetValue(projectSource, out fileEntry);
return fileEntry;
}
}
public void FileSaved(String fileName)
{
mFileWatcher.FileChanged(fileName);
ProcessFileChanges();
}
public void SetEntryObjFileName(FileEntry fileEntry, String objFilePath)
{
using (this.mMonitor.Enter())
{
if (objFilePath != fileEntry.mObjectFilePath)
{
if (fileEntry.mObjectFilePath != null)
mFileWatcher.RemoveWatch(fileEntry.mObjectFilePath, null);
String.NewOrSet!(fileEntry.mObjectFilePath, objFilePath);
mFileWatcher.WatchFile(objFilePath, null);
}
}
}
public void SetEntryBuildStringFileName(FileEntry fileEntry, String buildStringFilePath)
{
using (this.mMonitor.Enter())
{
if (buildStringFilePath != fileEntry.mBuildStringFilePath)
{
if (fileEntry.mBuildStringFilePath != null)
mFileWatcher.RemoveWatch(fileEntry.mBuildStringFilePath, null);
String.NewOrSet!(fileEntry.mBuildStringFilePath, buildStringFilePath);
mFileWatcher.WatchFile(buildStringFilePath, null);
}
}
}
public bool DoesEntryNeedRebuild(FileEntry fileEntry)
{
if (!mDoDependencyCheck)
return false;
if ((fileEntry.mClangFileRefs == null) || (fileEntry.mClangFileRefs.Count == 0))
return true;
int64 objFileTime = IDEUtils.GetLastModifiedTime(fileEntry.mObjectFilePath);
if (objFileTime == 0)
return true;
int64 highestRefTime = 0;
for (var fileRef in fileEntry.mClangFileRefs)
{
int64 fileTime = IDEUtils.GetLastModifiedTime(fileRef);
// Always rebuild if we don't even have a particular dep
if (fileTime == 0)
return true;
highestRefTime = Math.Max(highestRefTime, fileTime);
}
String[] productFileNames = scope String[] { fileEntry.mObjectFilePath, fileEntry.mBuildStringFilePath };
for (var productFileName in productFileNames)
{
int64 productFileTime = IDEUtils.GetLastModifiedTime(fileEntry.mBuildStringFilePath);
if (productFileTime == 0)
return true;
highestRefTime = Math.Max(highestRefTime, productFileTime);
}
return highestRefTime > objFileTime;
}
public void ProcessFileChanges()
{
while (true)
{
ProjectSource depFileChanged = (ProjectSource)mFileWatcher.PopChangedDependency();
if (depFileChanged == null)
break;
QueueCheckDependencies(depFileChanged, DepCheckerType.CDep);
//QueueProjectSource(depFileChanged);
/*ClangReparseSourceCommand command = new ClangReparseSourceCommand();
command.mProjectSource = depFileChanged;
QueueCommand(command);*/
mDoDependencyCheck = true;
}
}
public override void Update()
{
mAllowThreadStart = (mPairedCompiler == null) || (!mPairedCompiler.mThreadRunning);
base.Update();
mFileWatcher.Update();
String fileChanged = scope String();
while (true)
{
fileChanged.Clear();
if (!mFileWatcher.PopChangedFile(fileChanged))
break;
}
ProcessFileChanges();
}
}
}
#endif

View file

@ -0,0 +1,92 @@
#if false
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Beefy.widgets;
using IDE.Compiler;
namespace IDE.Clang
{
public class ClangHelper : CompilerBase
{
[StdCall, CLink]
static extern IntPtr ClangHelper_Create();
[StdCall, CLink]
static extern void ClangHelper_Delete(IntPtr clangHelper);
[StdCall, CLink]
static extern IntPtr ClangHelper_Classify(IntPtr clangHelper, char* fileName, void* elementTypeArray, int charLen, int cursorIdx);
[StdCall, CLink]
static extern IntPtr ClangHelper_FindDefinition(IntPtr clangHelper, char* fileName, int line, int column, out int outDefLine, out int outDefColumn);
[StdCall, CLink]
static extern IntPtr ClangHelper_Autocomplete(IntPtr clangHelper, char* fileName, int cursorIdx);
IntPtr mNativeClangHelper;
public this()
{
mNativeClangHelper = ClangHelper_Create();
}
public ~this()
{
ClangHelper_Delete(mNativeClangHelper);
mNativeClangHelper = IntPtr.Zero;
}
public string Classify(string fileName, EditWidgetContent.CharData[] charData, int cursorIdx)
{
fixed (EditWidgetContent.CharData* charDataPtr = charData)
{
IntPtr returnStringPtr = ClangHelper_Classify(mNativeClangHelper, fileName, charDataPtr, charData.Length, cursorIdx);
if (returnStringPtr == IntPtr.Zero)
return null;
return Marshal.PtrToStringAnsi(returnStringPtr);
}
}
public void FindDefinition(string fileName, int line, int column, out string defFileName, out int defLine, out int defColumn)
{
IntPtr fileNamePtr = ClangHelper_FindDefinition(mNativeClangHelper, fileName, line, column, out defLine, out defColumn);
if (fileNamePtr == null)
{
defFileName = null;
defLine = 0;
defColumn = 0;
return;
}
defFileName = Marshal.PtrToStringAnsi(fileNamePtr);
}
public string Autocomplete(string fileName, int cursorIdx)
{
IntPtr fileNamePtr = ClangHelper_Autocomplete(mNativeClangHelper, fileName, cursorIdx);
if (fileNamePtr == IntPtr.Zero)
return null;
return Marshal.PtrToStringAnsi(fileNamePtr);
}
protected override void ProcessQueue()
{
while (true)
{
Command command = null;
using (mMonitor.Enter())
{
if (mCommandQueue.Count == 0)
break;
command = mCommandQueue[0];
}
}
}
}
}
#endif

20
IDE/src/CmdTarget.bf Normal file
View file

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
namespace IDE
{
class CmdTarget
{
List<String> mQueue = new .() ~ DeleteContainerAndItems!(_);
public void Queue(StringView cmd)
{
mQueue.Add(new String(cmd));
}
public Result<void> Execute(StringView cmd)
{
return .Ok;
}
}
}

View file

@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using Beefy.utils;
namespace IDE
{
class ThreadWorkerContext
{
public Thread mThread;
public bool mThreadRunning;
public Action mOnThreadDone ~ delete _;
[ThreadStatic]
public static bool mBpSetThreadName;
public void DoBackground(ThreadStart threadStart, Action onThreadDone = null)
{
Debug.Assert(Thread.CurrentThread == IDEApp.sApp.mMainThread);
/*if (gApp.mMainWindow.IsKeyDown(.Control))
{
NOP!();
}*/
Debug.Assert(mOnThreadDone == null);
//mBfSystem.PerfZoneStart("BfCompiler.ThreadStart");
BeefPerf.Event("DoBackground:starting", "");
mOnThreadDone = onThreadDone;
mThreadRunning = true;
ThreadPool.QueueUserWorkItem(new () =>
{
if (!mBpSetThreadName)
{
String name = scope .();
Thread.CurrentThread.GetName(name);
BeefPerf.SetThreadName(name);
mBpSetThreadName = true;
}
BeefPerf.Event("DoBackground:threadStart", "");
mThreadRunning = true;
mThread = Thread.CurrentThread;
threadStart();
delete threadStart;
mThread = null;
mThreadRunning = false;
BeefPerf.Event("DoBackground:threadEnd", "");
});
//mBfSystem.PerfZoneEnd();
}
public void WaitForBackground()
{
if (mThreadRunning)
{
scope AutoBeefPerf("CancelBackground");
//mBfSystem.PerfZoneStart("BfCompiler.CancelBackground");
while (mThreadRunning)
{
// Lame
Thread.Sleep(20);
}
//mBfSystem.PerfZoneEnd();
}
if ((mOnThreadDone != null) && (Thread.CurrentThread == IDEApp.sApp.mMainThread))
{
mOnThreadDone();
delete mOnThreadDone;
mOnThreadDone = null;
}
}
public void CheckThreadDone()
{
if ((!mThreadRunning) && (mOnThreadDone != null))
{
mOnThreadDone();
delete mOnThreadDone;
mOnThreadDone = null;
}
}
}
public abstract class CommandQueueManager
{
protected class Command
{
}
public ThreadWorkerContext mThreadWorker = new .() ~ delete _;
public ThreadWorkerContext mThreadWorkerHi = new .() ~ delete _;
protected List<Command> mCommandQueue = new List<Command>() ~ DeleteContainerAndItems!(_);
protected bool mShuttingDown;
public bool mAllowThreadStart = true;
public Monitor mMonitor = new Monitor() ~ delete _;
public bool ThreadRunning
{
get
{
return mThreadWorker.mThreadRunning || mThreadWorkerHi.mThreadRunning;
}
}
public ~this()
{
using (mMonitor.Enter())
{
mShuttingDown = true;
ClearAndDeleteItems(mCommandQueue);
}
CancelBackground();
}
public virtual void RequestCancelBackground()
{
}
public void CancelBackground()
{
RequestCancelBackground();
WaitForBackground();
}
public void WaitForBackground()
{
mThreadWorker.WaitForBackground();
mThreadWorkerHi.WaitForBackground();
}
protected void QueueCommand(Command command)
{
using (mMonitor.Enter())
{
mCommandQueue.Add(command);
}
}
public bool HasQueuedCommands()
{
using (mMonitor.Enter())
{
return (mThreadWorker.mThreadRunning) || (mThreadWorkerHi.mThreadRunning) || (mCommandQueue.Count > 0);
}
}
public int32 GetCommandQueueSize()
{
using (mMonitor.Enter())
{
return (int32)mCommandQueue.Count;
}
}
protected abstract void DoProcessQueue();
public virtual void ProcessQueue()
{
DoProcessQueue();
}
public virtual void StartQueueProcessThread()
{
DoBackground(new => DoProcessQueue);
}
public bool IsPerformingBackgroundOperation()
{
return (mThreadWorker.mThreadRunning || mThreadWorkerHi.mThreadRunning);
}
public void DoBackground(ThreadStart threadStart, Action onThreadDone = null)
{
CancelBackground();
mThreadWorker.DoBackground(threadStart, onThreadDone);
}
public void DoBackgroundHi(ThreadStart threadStart, Action onThreadDone = null)
{
mThreadWorkerHi.DoBackground(threadStart, onThreadDone);
}
public void CheckThreadDone()
{
mThreadWorker.CheckThreadDone();
mThreadWorkerHi.CheckThreadDone();
}
public virtual void Update()
{
if (!mThreadWorker.mThreadRunning && !mThreadWorkerHi.mThreadRunning)
{
CheckThreadDone();
if (mAllowThreadStart)
{
if (mCommandQueue.Count > 0)
{
StartQueueProcessThread();
}
}
}
}
}
}

281
IDE/src/Commands.bf Normal file
View file

@ -0,0 +1,281 @@
using System;
using System.Collections.Generic;
using Beefy.widgets;
using Beefy.sys;
namespace IDE
{
public class KeyState : IHashable
{
public KeyCode mKeyCode;
public KeyFlags mKeyFlags;
public int GetHashCode()
{
return (int)mKeyCode | (int)mKeyFlags << 16;
}
public static bool operator==(KeyState val1, KeyState val2)
{
return (val1.mKeyCode == val2.mKeyCode) &&
(val1.mKeyFlags == val2.mKeyFlags);
}
public override void ToString(String strBuffer)
{
if (mKeyFlags.HasFlag(.Ctrl))
strBuffer.Append("Ctrl+");
if (mKeyFlags.HasFlag(.Alt))
strBuffer.Append("Alt+");
if (mKeyFlags.HasFlag(.Shift))
strBuffer.Append("Shift+");
mKeyCode.ToString(strBuffer);
}
public static void ToString(List<KeyState> keyStates, String strBuffer)
{
for (int i < keyStates.Count)
{
if (i > 0)
strBuffer.Append(", ");
keyStates[i].ToString(strBuffer);
}
}
public static bool Parse(StringView keys, List<KeyState> keyList)
{
bool success = true;
for (let keyStateStr in keys.Split(','))
{
let keyState = new KeyState();
for (var keyStr in keyStateStr.Split('+'))
{
keyStr.Trim();
if (keyStr.Equals("Ctrl", true))
keyState.mKeyFlags |= .Ctrl;
else if (keyStr.Equals("Alt", true))
keyState.mKeyFlags |= .Alt;
else if (keyStr.Equals("Shift", true))
keyState.mKeyFlags |= .Shift;
else
{
let result = KeyCode.Parse(keyStr);
if (result case .Ok(let keyCode))
keyState.mKeyCode = keyCode;
else
success = false;
}
}
keyList.Add(keyState);
}
return success;
}
public KeyState Clone()
{
var dup = new KeyState();
dup.mKeyCode = mKeyCode;
dup.mKeyFlags = mKeyFlags;
return dup;
}
}
class IDECommandBase
{
public CommandMap mParent;
public KeyState mBoundKeyState;
public override void ToString(String strBuffer)
{
if (mParent == null)
return;
mParent.ToString(strBuffer);
if (mBoundKeyState != null)
{
if (!strBuffer.IsEmpty)
strBuffer.Append(", ");
mBoundKeyState.ToString(strBuffer);
}
}
}
class IDECommand : IDECommandBase
{
public enum ContextFlags
{
None = 0,
Editor = 1
}
public String mName ~ delete _;
public Action mAction ~ delete _;
public SysMenu mMenuItem;
public ContextFlags mContextFlags;
public IDECommand mNext;
}
class CommandMap : IDECommandBase
{
public Dictionary<KeyState, IDECommandBase> mMap = new .() ~ delete _;
public void Clear()
{
for (let val in mMap.Values)
{
if (var cmdMap = val as CommandMap)
delete cmdMap;
else
{
var ideCommand = (IDECommand)val;
val.mBoundKeyState = null;
val.mParent = null;
ideCommand.mNext = null;
}
}
mMap.Clear();
}
public ~this()
{
Clear();
}
}
class KeyChordState
{
public KeyState mKeyState;
public CommandMap mCommandMap;
}
class Commands
{
public Dictionary<String, IDECommand> mCommandMap = new .() ~
{
for (let val in _.Values)
delete val;
delete _;
};
public CommandMap mKeyMap = new .() ~ delete _;
void Add(StringView name, Action act, IDECommand.ContextFlags contextFlags = .None)
{
let cmd = new IDECommand();
cmd.mName = new String(name);
cmd.mAction = act;
cmd.mContextFlags = contextFlags;
mCommandMap[cmd.mName] = cmd;
}
public void Init()
{
Add("About", new => gApp.ShowAbout);
Add("Autocomplete", new => gApp.Cmd_ShowAutoComplete);
Add("Bookmark Next", new => gApp.Cmd_NextBookmark, .Editor);
Add("Bookmark Prev", new => gApp.Cmd_PrevBookmark, .Editor);
Add("Bookmark Toggle", new => gApp.Cmd_ToggleBookmark, .Editor);
Add("Bookmark Clear", new => gApp.Cmd_ClearBookmarks, .Editor);
Add("Break All", new => gApp.[Friend]Cmd_Break);
Add("Breakpoint Memory", new () => { gApp.mBreakpointPanel.AddMemoryBreakpoint(gApp.[Friend]GetCurrentWindow()); }, .Editor);
Add("Breakpoint Symbol", new () => { gApp.mBreakpointPanel.AddSymbolBreakpoint(gApp.[Friend]GetCurrentWindow()); }, .Editor);
Add("Breakpoint Toggle Thread", new => gApp.[Friend]ToggleThreadBreakpoint, .Editor);
Add("Breakpoint Toggle", new => gApp.[Friend]ToggleBreakpoint, .Editor);
Add("Build Solution", new => gApp.[Friend]Compile);
Add("Cancel Build", new => gApp.[Friend]CancelBuild);
Add("Clean Beef", new => gApp.Cmd_CleanBeef);
Add("Clean", new => gApp.Cmd_Clean);
Add("Close All Windows", new () => { gApp.[Friend]TryCloseAllDocuments(); });
Add("Close Window", new () => { gApp.[Friend]TryCloseCurrentDocument(); });
Add("Close Workspace", new => gApp.[Friend]Cmd_CloseWorkspaceAndSetupNew);
Add("Compile File", new => gApp.Cmd_CompileFile);
Add("Debug All Tests", new () => { gApp.[Friend]RunTests(true); });
Add("Exit", new => gApp.[Friend]Cmd_Exit);
Add("Find All References", new => gApp.Cmd_FindAllReferences);
Add("Find Class", new => gApp.Cmd_FindClass);
Add("Find in Document", new => gApp.Cmd_Document__Find);
Add("Find in Files", new => gApp.Cmd_Find);
Add("Find Next", new => gApp.Cmd_FindNext);
Add("Find Prev", new => gApp.Cmd_FindPrev);
Add("Goto Definition", new => gApp.GoToDefinition);
Add("Goto Line", new => gApp.Cmd_GotoLine);
Add("Goto Method", new => gApp.Cmd_GotoMethod);
Add("Goto Next Item", new => gApp.Cmd_GotoNextItem);
Add("Launch Process", new => gApp.[Friend]DoLaunch);
Add("Make Lowercase", new () => { gApp.[Friend]ChangeCase(false); });
Add("Make Uppercase", new () => { gApp.[Friend]ChangeCase(true); });
Add("Match Brace Select", new => gApp.Cmd_MatchBrace);
Add("Match Brace", new => gApp.Cmd_MatchBrace);
Add("Navigate Backwards", new => gApp.[Friend]NavigateBackwards);
Add("Navigate Forwards", new => gApp.[Friend]NavigateForwards);
Add("New Debug Session", new => gApp.[Friend]Cmd_NewDebugSession);
Add("New File", new => gApp.Cmd_NewFile);
Add("New Project", new => gApp.Cmd_NewProject);
Add("New Workspace", new => gApp.Cmd_NewWorkspace);
Add("New View Into File", new => gApp.Cmd_NewFileView);
Add("Next Document Panel", new => gApp.[Friend]DoShowNextDocumentPanel);
Add("Open Corresponding", new => gApp.[Friend]OpenCorresponding);
Add("Open Crash Dump", new => gApp.OpenCrashDump);
Add("Open Debug Session", new => gApp.DoOpenDebugSession);
Add("Open File in Workspace", new => gApp.[Friend]ShowOpenFileInSolutionDialog);
Add("Open File", new => gApp.OpenFile);
Add("Open Project", new => gApp.Cmd_OpenProject);
Add("Open Workspace", new => gApp.OpenWorkspace);
Add("Profile", new => gApp.[Friend]DoProfile);
Add("Reformat Document", new => gApp.Cmd_ReformatDocument);
Add("Remove All Breakpoints", new => gApp.[Friend]RemoveAllBreakpoints);
Add("Rename Item", new => gApp.Cmd_RenameItem);
Add("Rename Symbol", new => gApp.Cmd_RenameSymbol);
Add("Replace in Document", new => gApp.Cmd_Document__Replace);
Add("Replace in Files", new => gApp.Cmd_Replace);
Add("Report Memory", new => gApp.[Friend]ReportMemory);
Add("Run All Tests", new => gApp.Cmd_RunAllTests);
Add("Run To Cursor", new => gApp.[Friend]RunToCursor);
Add("Run Without Compiling", new => gApp.[Friend]RunWithoutCompiling);
Add("Save All", new () => { gApp.SaveAll(); });
Add("Save As", new () => { gApp.SaveAs(); });
Add("Save File", new => gApp.SaveFile);
Add("Select Configuration", new => gApp.SelectConfig);
Add("Select Platform", new => gApp.SelectPlatform);
Add("Set Next Statement", new => gApp.[Friend]SetNextStatement);
Add("Settings", new => gApp.ShowSettings);
Add("Show Auto Watches", new => gApp.ShowAutoWatches);
Add("Show Autocomplete Panel", new => gApp.ShowAutoCompletePanel);
Add("Show Breakpoints", new => gApp.ShowBreakpoints);
Add("Show Call Stack", new => gApp.ShowCallstack);
Add("Show Class View", new => gApp.ShowClassViewPanel);
Add("Show Current", new => gApp.Cmd_ShowCurrent);
Add("Show Disassembly", new => gApp.[Friend]ShowDisassemblyAtStack);
Add("Show File Externally", new => gApp.Cmd_ShowFileExternally);
Add("Show Find Results", new => gApp.ShowFindResults);
Add("Show Fixit", new => gApp.Cmd_ShowFixit);
Add("Show Immediate", new => gApp.ShowImmediatePanel);
Add("Show Memory", new => gApp.ShowMemory);
Add("Show Modules", new => gApp.ShowModules);
Add("Show Output", new => gApp.ShowOutput);
Add("Show Profiler", new => gApp.ShowProfilePanel);
Add("Show QuickWatch", new => gApp.ShowQuickWatch);
Add("Show Threads", new => gApp.ShowThreads);
Add("Show Watches", new => gApp.ShowWatches);
Add("Show Workspace Explorer", new => gApp.ShowWorkspacePanel);
Add("Split View", new => gApp.[Friend]SplitView);
Add("Start Debugging", new => gApp.[Friend]RunWithCompiling);
Add("Start Without Debugging", new => gApp.[Friend]RunWithoutCompiling);
Add("Step Into", new => gApp.[Friend]StepInto);
Add("Step Out", new => gApp.[Friend]StepOut);
Add("Step Over", new => gApp.[Friend]StepOver);
Add("Stop Debugging", new => gApp.[Friend]StopRunning);
Add("Tab First", new => gApp.[Friend]TabFirst);
Add("Tab Last", new => gApp.[Friend]TabLast);
Add("Tab Next", new => gApp.[Friend]TabNext);
Add("Tab Prev", new => gApp.[Friend]TabPrev);
Add("View White Space", new => gApp.Cmd_ViewWhiteSpace);
Add("Zoom In", new => gApp.Cmd_ZoomIn);
Add("Zoom Out", new => gApp.Cmd_ZoomOut);
Add("Zoom Reset", new => gApp.Cmd_ZoomReset);
Add("Attach to Process", new => gApp.[Friend]DoAttach);
Add("Test Enable Console", new => gApp.Cmd_TestEnableConsole);
Add("Test Include Ignored", new => gApp.Cmd_TestIncludeIgnored);
}
}
}

View file

@ -0,0 +1,650 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
using Beefy.widgets;
using Beefy;
using Beefy.utils;
namespace IDE.Compiler
{
//public class Bf
public class BfCompiler : CompilerBase
{
enum OptionFlags : int32
{
EmitDebugInfo = 1,
EmitLineInfo = 2,
WriteIR = 4,
GenerateOBJ = 8,
NoFramePointerElim = 0x10,
ClearLocalVars = 0x20,
RuntimeChecks = 0x40,
EmitDynamicCastCheck = 0x80,
EnableObjectDebugFlags = 0x100,
EmitObjectAccessCheck = 0x200,
EnableCustodian = 0x400,
EnableRealtimeLeakCheck = 0x800,
EnableSideStack = 0x1000,
EnableHotSwapping = 0x2000,
IncrementalBuild = 0x4000,
DebugAlloc = 0x8000
}
[StdCall, CLink]
static extern bool BfCompiler_Compile(void* bfCompiler, void* bfPassInstance, char8* outputDirectory);
[StdCall, CLink]
static extern bool BfCompiler_ClearResults(void* bfCompiler);
[StdCall, CLink]
static extern bool BfCompiler_VerifyTypeName(void* bfCompiler, char8* typeName, int32 cursorPos);
[StdCall, CLink]
static extern bool BfCompiler_ClassifySource(void* bfCompiler, void* bfPassInstance, void* bfParser, void* bfResolvePassData, void* char8Data);
[StdCall, CLink]
static extern char8* BfCompiler_GetAutocompleteInfo(void* bfCompiler);
[StdCall, CLink]
static extern char8* BfCompiler_GetSymbolReferences(void* bfCompiler, void* bfPassInstance, void* bfResolvePassData);
[StdCall, CLink]
static extern void BfCompiler_Cancel(void* bfCompiler);
[StdCall, CLink]
static extern void BfCompiler_ClearCompletionPercentage(void* bfCompiler);
[StdCall, CLink]
static extern float BfCompiler_GetCompletionPercentage(void* bfCompiler);
[StdCall, CLink]
static extern int32 BfCompiler_GetCompileRevision(void* bfCompiler);
[StdCall, CLink]
static extern void BfCompiler_Delete(void* bfCompiler);
[StdCall, CLink]
static extern void BfCompiler_ClearBuildCache(void* bfCompiler);
[StdCall, CLink]
static extern char8* BfCompiler_GetOutputFileNames(void* bfCompiler, void* bfProject, out bool hadOutputChanges);
[StdCall, CLink]
static extern char8* BfCompiler_GetUsedOutputFileNames(void* bfCompiler, void* bfProject, bool flushQueuedHotFiles, out bool hadOutputChanges);
[StdCall, CLink]
static extern char8* BfCompiler_GetTypeDefList(void* bfCompiler);
[StdCall, CLink]
static extern char8* BfCompiler_GetTypeDefMatches(void* bfCompiler, char8* searchStr);
[StdCall, CLink]
static extern char8* BfCompiler_GetTypeDefInfo(void* bfCompiler, char8* typeDefName);
[StdCall, CLink]
static extern void BfCompiler_SetOptions(void* bfCompiler,
void* hotProject, int32 hotIdx, int32 machineType, int32 toolsetType, int32 simdSetting, int32 allocStackCount, int32 maxWorkerThreads,
OptionFlags optionsFlags, char8* mallocName, char8* freeName);
[StdCall, CLink]
static extern void BfCompiler_ForceRebuild(void* bfCompiler);
public enum HotTypeFlags
{
None = 0,
UserNotUsed = 1,
UserUsed = 2,
Heap = 4,
};
[StdCall, CLink]
static extern bool BfCompiler_GetHasHotPendingDataChanges(void* bfCompiler);
[StdCall, CLink]
static extern void BfCompiler_HotCommit(void* bfCompiler);
public enum HotResolveFlags
{
None = 0,
HadDataChanges = 1
}
[StdCall, CLink]
static extern void BfCompiler_HotResolve_Start(void* bfCompiler, int32 flags);
[StdCall, CLink]
static extern void BfCompiler_HotResolve_AddActiveMethod(void* bfCompiler, char8* methodName);
[StdCall, CLink]
static extern void BfCompiler_HotResolve_AddDelegateMethod(void* bfCompiler, char8* methodName);
[StdCall, CLink]
static extern void BfCompiler_HotResolve_ReportType(void* bfCompiler, int typeId, int usageKind);
[StdCall, CLink]
static extern void BfCompiler_HotResolve_ReportTypeRange(void* bfCompiler, char8* typeName, int usageKind);
[StdCall, CLink]
static extern char8* BfCompiler_HotResolve_Finish(void* bfCompiler);
class SetPassInstanceCommand : Command
{
public BfPassInstance mPassInstance;
}
class SetupProjectSettingsCommand : Command
{
public Project mProject;
}
class DeleteBfProjectCommand : Command
{
public BfProject mBfProject;
}
class RefreshViewCommand : Command
{
}
class SetWorkspaceOptionsCommand : Command
{
public BfProject mHotBfProject;
public int32 mHotIdx;
}
public void* mNativeBfCompiler;
public bool mIsResolveOnly;
public BfSystem mBfSystem;
bool mWantsRemoveOldData;
public this(void* nativeBfCompiler)
{
mNativeBfCompiler = nativeBfCompiler;
}
public ~this()
{
BfCompiler_Delete(mNativeBfCompiler);
mNativeBfCompiler = null;
if (mCommandQueue.Count > 0)
{
NOP!();
}
}
public bool Compile(BfPassInstance passInstance, String outputDirectory)
{
bool success = BfCompiler_Compile(mNativeBfCompiler, passInstance.mNativeBfPassInstance, outputDirectory);
passInstance.mCompileSucceeded = success;
passInstance.mDidCompile = true;
return success;
}
public void ClearResults()
{
BfCompiler_ClearResults(mNativeBfCompiler);
}
public bool ClassifySource(BfPassInstance bfPassInstance, BfParser parser, BfResolvePassData resolvePassData, EditWidgetContent.CharData[] char8Data)
{
void* nativeResolvePassData = null;
if (resolvePassData != null)
nativeResolvePassData = resolvePassData.mNativeResolvePassData;
EditWidgetContent.CharData* char8DataPtr = (char8Data != null) ? char8Data.CArray() : null;
return BfCompiler_ClassifySource(mNativeBfCompiler, bfPassInstance.mNativeBfPassInstance, (parser != null) ? parser.mNativeBfParser : null, nativeResolvePassData, char8DataPtr);
}
public bool VerifyTypeName(String typeName, int cursorPos)
{
return BfCompiler_VerifyTypeName(mNativeBfCompiler, typeName, (.)cursorPos);
}
public void GetAutocompleteInfo(String outAutocompleteInfo)
{
char8* result = BfCompiler_GetAutocompleteInfo(mNativeBfCompiler);
scope String(result).MoveTo(outAutocompleteInfo);
}
public void GetSymbolReferences(BfPassInstance passInstance, BfResolvePassData resolvePassData, String outSymbolReferences)
{
char8* result = BfCompiler_GetSymbolReferences(mNativeBfCompiler, passInstance.mNativeBfPassInstance, resolvePassData.mNativeResolvePassData);
scope String(result).MoveTo(outSymbolReferences);
}
/*public void UpdateRenameSymbols(BfPassInstance passInstance, BfResolvePassData resolvePassData)
{
BfCompiler_UpdateRenameSymbols(mNativeBfCompiler, passInstance.mNativeBfPassInstance, resolvePassData.mNativeResolvePassData);
}*/
public void GetOutputFileNames(BfProject project, bool flushQueuedHotFiles, out bool hadOutputChanges, List<String> outFileNames)
{
char8* result = BfCompiler_GetUsedOutputFileNames(mNativeBfCompiler, project.mNativeBfProject, flushQueuedHotFiles, out hadOutputChanges);
if (result == null)
return;
String fileNamesStr = scope String();
fileNamesStr.Append(result);
if (fileNamesStr.Length == 0)
return;
List<StringView> stringViews = scope List<StringView>(fileNamesStr.Split('\n'));
for (var strView in stringViews)
outFileNames.Add(new String(strView));
}
public void SetOptions(BfProject hotProject, int32 hotIdx,
int32 machineType, int32 toolsetType, int32 simdSetting, int32 allocStackCount, int32 maxWorkerThreads,
OptionFlags optionFlags, String mallocFuncName, String freeFuncName)
{
BfCompiler_SetOptions(mNativeBfCompiler,
(hotProject != null) ? hotProject.mNativeBfProject : null, hotIdx,
machineType, toolsetType, simdSetting, allocStackCount, maxWorkerThreads, optionFlags, mallocFuncName, freeFuncName);
}
public void ForceRebuild()
{
BfCompiler_ForceRebuild(mNativeBfCompiler);
}
public void QueueSetPassInstance(BfPassInstance passInstance)
{
SetPassInstanceCommand command = new SetPassInstanceCommand();
command.mPassInstance = passInstance;
QueueCommand(command);
}
public void QueueSetupProjectSettings(Project project)
{
SetupProjectSettingsCommand command = new SetupProjectSettingsCommand();
command.mProject = project;
QueueCommand(command);
}
public void QueueDeleteBfProject(BfProject bfProject)
{
DeleteBfProjectCommand command = new DeleteBfProjectCommand();
command.mBfProject = bfProject;
QueueCommand(command);
}
public void QueueRefreshViewCommand()
{
QueueCommand(new RefreshViewCommand());
}
public void QueueSetWorkspaceOptions(Project hotProject, int32 hotIdx)
{
BfProject hotBfProject = null;
if (hotProject != null)
hotBfProject = mBfSystem.GetBfProject(hotProject);
var command = new SetWorkspaceOptionsCommand();
command.mHotBfProject = hotBfProject;
command.mHotIdx = hotIdx;
QueueCommand(command);
}
protected override void DoProcessQueue()
{
BfPassInstance passInstance = null;
bool didPassInstanceAlloc = false;
mBfSystem.Lock(0);
//Debug.WriteLine("Starting Beef Thread {0}", Thread.CurrentThread.Id);
while (true)
{
Command command = null;
using (mMonitor.Enter())
{
if (mCommandQueue.Count == 0)
break;
command = mCommandQueue[0];
}
if (command is SetPassInstanceCommand)
{
var setPassInstanceCommand = (SetPassInstanceCommand)command;
passInstance = setPassInstanceCommand.mPassInstance;
}
else if (passInstance == null)
{
passInstance = mBfSystem.CreatePassInstance("ProcessQueue");
didPassInstanceAlloc = true;
}
if (command is SetupProjectSettingsCommand)
{
var setupProjectSettingsCommand = (SetupProjectSettingsCommand)command;
gApp.SetupBeefProjectSettings(mBfSystem, this, setupProjectSettingsCommand.mProject);
}
if (command is DeleteBfProjectCommand)
{
var deleteBfProjectCommand = (DeleteBfProjectCommand)command;
deleteBfProjectCommand.mBfProject.Dispose();
delete deleteBfProjectCommand.mBfProject;
}
if (command is ProjectSourceCommand)
ProjectSourceCommandBlock:
{
var projectSourceCommand = (ProjectSourceCommand)command;
bool worked = true;
String sourceFilePath = scope String();
var projectSource = projectSourceCommand.mProjectSource;
if (projectSource.mIncludeKind != .Ignore)
{
using (projectSource.mProject.mMonitor.Enter())
{
projectSourceCommand.mProjectSource.GetFullImportPath(sourceFilePath);
}
bool canMoveSourceString = true;
IdSpan char8IdData = projectSourceCommand.mSourceCharIdData;
String data = projectSourceCommand.mSourceString;
if (char8IdData.IsEmpty)
{
data = scope:ProjectSourceCommandBlock String();
if (gApp.LoadTextFile(sourceFilePath, data) case .Err)
data = null;
if (data != null)
{
data.EnsureNullTerminator();
char8IdData = IdSpan.GetDefault((int32)data.Length);
defer:ProjectSourceCommandBlock char8IdData.Dispose();
var editData = gApp.GetEditData(projectSource, false);
using (gApp.mMonitor.Enter())
{
editData.SetSavedData(data, char8IdData);
}
canMoveSourceString = false;
}
}
if (data == null)
{
String msg = new String();
msg.AppendF("FAILED TO LOAD FILE: {0}", sourceFilePath);
mQueuedOutput.Add(msg);
passInstance.mFailed = true;
}
if ((!mIsResolveOnly) && (data != null))
IDEApp.sApp.mWorkspace.ProjectSourceCompiled(projectSource, data, char8IdData, canMoveSourceString);
var bfParser = mBfSystem.CreateParser(projectSourceCommand.mProjectSource);
if (data != null)
bfParser.SetSource(data, sourceFilePath);
else
bfParser.SetSource("", sourceFilePath);
bfParser.SetCharIdData(ref char8IdData);
worked &= bfParser.Parse(passInstance, false);
worked &= bfParser.Reduce(passInstance);
worked &= bfParser.BuildDefs(passInstance, null, false);
// Do this to make sure we re-trigger errors in parse/reduce/builddefs
if (!worked)
projectSource.HasChangedSinceLastCompile = true;
}
}
if (command is ProjectSourceRemovedCommand)
{
var fileRemovedCommand = (ProjectSourceRemovedCommand)command;
var bfParser = mBfSystem.FileRemoved(fileRemovedCommand.mProjectSource);
if (bfParser != null)
{
bfParser.RemoveDefs();
delete bfParser;
mWantsRemoveOldData = true;
}
}
if (command is CompileCommand)
{
var compileCommand = (CompileCommand)command;
Compile(passInstance, compileCommand.mOutputDirectory);
mBfSystem.RemoveOldParsers();
mBfSystem.RemoveOldData();
}
if (command is ResolveAllCommand)
{
var resolvePassData = BfResolvePassData.Create(ResolveType.Classify);
// If we get canceled then try again after waiting a couple updates
if (!ClassifySource(passInstance, null, resolvePassData, null))
QueueDeferredResolveAll();
delete resolvePassData;
mBfSystem.RemoveOldParsers();
mBfSystem.RemoveOldData();
}
if (command is SetWorkspaceOptionsCommand)
{
var setWorkspaceOptionsCommand = (SetWorkspaceOptionsCommand)command;
var workspace = IDEApp.sApp.mWorkspace;
using (workspace.mMonitor.Enter())
{
HandleOptions(setWorkspaceOptionsCommand.mHotBfProject, setWorkspaceOptionsCommand.mHotIdx);
}
}
if (command is RefreshViewCommand)
{
mWantsActiveViewRefresh = true;
}
using (mMonitor.Enter())
{
delete command;
if (!mShuttingDown)
{
var poppedCmd = mCommandQueue.PopFront();
Debug.Assert(poppedCmd == command);
}
}
}
mBfSystem.Unlock();
if (didPassInstanceAlloc)
delete passInstance;
}
void HandleOptions(BfProject hotBfProject, int32 hotIdx)
{
//Debug.WriteLine("HandleOptions");
var options = IDEApp.sApp.GetCurWorkspaceOptions();
bool enableObjectDebugFlags = options.mEnableObjectDebugFlags;
bool emitObjectAccessCheck = options.mEmitObjectAccessCheck && enableObjectDebugFlags;
OptionFlags optionFlags = default;
void SetOpt(bool val, OptionFlags optionFlag)
{
if (val)
optionFlags |= optionFlag;
//Debug.WriteLine(" SetOpt {0:X} {1:X}", (int)optionFlags, (int)optionFlag);
}
SetOpt(options.mIncrementalBuild, .IncrementalBuild);
SetOpt(options.mEmitDebugInfo == .Yes, .EmitDebugInfo);
SetOpt((options.mEmitDebugInfo == .Yes) || (options.mEmitDebugInfo == .LinesOnly), .EmitLineInfo);
if (gApp.mConfig_NoIR)
{
SetOpt(true, .GenerateOBJ);
}
else
{
SetOpt((options.mIntermediateType == .IRCode) || (options.mIntermediateType == .ObjectAndIRCode), .WriteIR);
SetOpt((options.mIntermediateType == .Object) || (options.mIntermediateType == .ObjectAndIRCode), .GenerateOBJ);
}
SetOpt(options.mNoOmitFramePointers, .NoFramePointerElim);
SetOpt(options.mInitLocalVariables, .ClearLocalVars);
SetOpt(options.mRuntimeChecks, .RuntimeChecks);
SetOpt(options.mEmitDynamicCastCheck, .EmitDynamicCastCheck);
SetOpt(enableObjectDebugFlags, .EnableObjectDebugFlags);
SetOpt(emitObjectAccessCheck, .EmitObjectAccessCheck);
#if BF_PLATFORM_WINDOWS
SetOpt(options.mEnableRealtimeLeakCheck, .EnableRealtimeLeakCheck);
#endif
SetOpt(options.mEnableSideStack, .EnableSideStack);
#if !CLI
SetOpt(options.mAllowHotSwapping, .EnableHotSwapping);
#endif
String mallocLinkName;
String freeLinkName;
switch (options.mAllocType)
{
case .Debug:
optionFlags |= .DebugAlloc;
mallocLinkName = "";
freeLinkName = "";
case .CRT:
mallocLinkName = "malloc";
freeLinkName = "free";
case .JEMalloc:
mallocLinkName = "je_malloc";
freeLinkName = "je_free";
case .TCMalloc:
mallocLinkName = "tcmalloc";
freeLinkName = "tcfree";
case .Custom:
mallocLinkName = options.mAllocMalloc;
freeLinkName = options.mAllocFree;
}
//Debug.WriteLine("HandleOptions SetOptions:{0:X}", (int)optionFlags);
SetOptions(hotBfProject, hotIdx,
(int32)options.mMachineType, (int32)options.mToolsetType, (int32)options.mBfSIMDSetting, (int32)options.mAllocStackTraceDepth, (int32)gApp.mSettings.mCompilerSettings.mWorkerThreads,
optionFlags, mallocLinkName, freeLinkName);
if (!mIsResolveOnly)
{
for (let typeOption in gApp.mWorkspace.mBeefGlobalOptions.mDistinctBuildOptions)
mBfSystem.AddTypeOptions(typeOption);
for (let typeOption in options.mDistinctBuildOptions)
mBfSystem.AddTypeOptions(typeOption);
}
}
public override void StartQueueProcessThread()
{
// This causes the current view to do a full refresh every keystroke.
// I think it's not needed...
//mWantsActiveViewRefresh = true;
base.StartQueueProcessThread();
}
public override void RequestCancelBackground()
{
if ([Friend]mThreadWorker.mThreadRunning)
{
/*if (gApp.mMainWindow.IsKeyDown(.Control))
{
NOP!();
}*/
if (mNativeBfCompiler != null)
BfCompiler_Cancel(mNativeBfCompiler);
}
}
public void ClearCompletionPercentage()
{
BfCompiler_ClearCompletionPercentage(mNativeBfCompiler);
}
public float GetCompletionPercentage()
{
return BfCompiler_GetCompletionPercentage(mNativeBfCompiler);
}
public int32 GetCompileRevision()
{
return BfCompiler_GetCompileRevision(mNativeBfCompiler);
}
public void GetTypeDefList(String outStr)
{
outStr.Append(BfCompiler_GetTypeDefList(mNativeBfCompiler));
}
public void GetTypeDefMatches(String searchStr, String outStr)
{
outStr.Append(BfCompiler_GetTypeDefMatches(mNativeBfCompiler, searchStr));
}
public void GetTypeDefInfo(String typeDefName, String outStr)
{
outStr.Append(BfCompiler_GetTypeDefInfo(mNativeBfCompiler, typeDefName));
}
public void ClearBuildCache()
{
BfCompiler_ClearBuildCache(mNativeBfCompiler);
}
public bool GetHasHotPendingDataChanges()
{
return BfCompiler_GetHasHotPendingDataChanges(mNativeBfCompiler);
}
public void HotCommit()
{
BfCompiler_HotCommit(mNativeBfCompiler);
}
public void HotResolve_Start(HotResolveFlags flags)
{
BfCompiler_HotResolve_Start(mNativeBfCompiler, (.)flags);
}
public void HotResolve_AddActiveMethod(char8* methodName)
{
BfCompiler_HotResolve_AddActiveMethod(mNativeBfCompiler, methodName);
}
public void HotResolve_AddDelegateMethod(char8* methodName)
{
BfCompiler_HotResolve_AddDelegateMethod(mNativeBfCompiler, methodName);
}
public void HotResolve_ReportType(int typeId, HotTypeFlags flags)
{
BfCompiler_HotResolve_ReportType(mNativeBfCompiler, typeId, (int32)flags);
}
public void HotResolve_ReportTypeRange(char8* typeName, HotTypeFlags flags)
{
BfCompiler_HotResolve_ReportTypeRange(mNativeBfCompiler, typeName, (int32)flags);
}
public void HotResolve_Finish(String result)
{
char8* resultCStr = BfCompiler_HotResolve_Finish(mNativeBfCompiler);
result.Append(resultCStr);
}
public override void Update()
{
base.Update();
if (!ThreadRunning)
{
if (mWantsRemoveOldData)
{
mBfSystem.RemoveOldData();
mWantsRemoveOldData = false;
}
}
}
}
}

View file

@ -0,0 +1,352 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Beefy.widgets;
using Beefy.utils;
using IDE.ui;
using System.IO;
using System.Threading;
namespace IDE.Compiler
{
public enum BfSourceElementType : uint8
{
Normal,
Keyword,
Literal,
Identifier,
Type,
Comment,
Method,
TypeRef
}
public enum ResolveType
{
None,
Classify,
ClassifyFullRefresh,
Autocomplete,
Autocomplete_HighPri,
GoToDefinition,
GetSymbolInfo,
RenameSymbol,
ShowFileSymbolReferences,
GetNavigationData,
GetCurrentLocation,
GetFixits,
GetTypeDefList,
GetTypeDefInto,
GetVarType
}
public class ResolveParams
{
public ResolveType mResolveType;
public int32 mOverrideCursorPos = -1;
public bool mInDeferredList;
public int32 mLocalId = -1;
public String mReplaceStr ~ delete _;
public String mTypeDef ~ delete _;
public int32 mFieldIdx = -1;
public int32 mMethodIdx = -1;
public int32 mPropertyIdx = -1;
public int32 mTypeGenericParamIdx = -1;
public int32 mMethodGenericParamIdx = -1;
public String mOutFileName ~ delete _;
public int32 mOutLine;
public int32 mOutLineChar;
public String mNavigationData ~ delete _;
public String mAutocompleteInfo ~ delete _;
public WaitEvent mWaitEvent ~ delete _;
public BfPassInstance mPassInstance ~ delete _;
public EditWidgetContent.CharData[] mCharData ~ delete _;
public IdSpan mCharIdSpan ~ _.Dispose();
public BfParser mParser;
public String mDocumentationName ~ delete _;
public bool mCancelled;
public int32 mTextVersion = -1;
public bool mIsUserRequested;
}
public class BfParser : ILeakIdentifiable
{
static int32 sIdx;
public int32 mIdx = sIdx++;
public void ToLeakString(String str)
{
str.AppendF("Idx:{0}", mIdx);
}
[StdCall, CLink]
static extern void BfSystem_DeleteParser(void* bfSystem, void* bfParser);
[StdCall, CLink]
static extern void BfParser_SetSource(void* bfParser, char8* data, int32 length, char8* fileName);
[StdCall, CLink]
static extern void BfParser_SetCharIdData(void* bfParser, uint8* data, int32 length);
[StdCall, CLink]
static extern void BfParser_SetNextRevision(void* bfParser, void* nextParser);
[StdCall, CLink]
static extern bool BfParser_SetCursorIdx(void* bfParser, int32 cursorIdx);
[StdCall, CLink]
static extern bool BfParser_SetAutocomplete(void* bfParser, int32 cursorIdx);
[StdCall, CLink]
static extern bool BfParser_SetIsClassifying(void* bfParser);
[StdCall, CLink]
static extern bool BfParser_Parse(void* bfParser, void* bfPassInstance, bool compatMode);
[StdCall, CLink]
static extern bool BfParser_Reduce(void* bfParser, void* bfPassInstance);
[StdCall, CLink]
static extern char8* BfParser_Format(void* bfParser, int32 formatEnd, int32 formatStart, out int32* outCharMapping);
[StdCall, CLink]
static extern char8* BfParser_GetDebugExpressionAt(void* bfParser, int32 cursorIdx);
[StdCall, CLink]
static extern void* BfParser_CreateResolvePassData(void* bfSystem, int32 resolveType);
[StdCall, CLink]
static extern bool BfParser_BuildDefs(void* bfParser, void* bfPassInstance, void* bfResolvePassData, bool fullRefresh);
[StdCall, CLink]
static extern void BfParser_RemoveDefs(void* bfParser);
[StdCall, CLink]
static extern void BfParser_ClassifySource(void* bfParser, void* elementTypeArray, bool preserveFlags);
[StdCall, CLink]
static extern void BfParser_GenerateAutoCompletionFrom(void* bfParser, int32 srcPosition);
[StdCall, CLink]
static extern void BfParser_SetCompleteParse(void* bfParser);
public BfSystem mSystem;
public void* mNativeBfParser;
public bool mIsUsed;
public String mFileName ~ delete _;
public ProjectSource mProjectSource;
public this(void* nativeBfParser)
{
mNativeBfParser = nativeBfParser;
}
public ~this()
{
if (mNativeBfParser != null)
BfSystem_DeleteParser(mSystem.mNativeBfSystem, mNativeBfParser);
}
public void Detach()
{
mNativeBfParser = null;
}
public void SetSource(String data, String fileName)
{
if (fileName.Contains("main4.cs"))
{
}
Debug.Assert(!mIsUsed);
mIsUsed = true;
BfParser_SetSource(mNativeBfParser, data, (int32)data.Length, fileName);
}
public void SetCharIdData(ref IdSpan char8IdData)
{
char8IdData.Prepare();
uint8* data = char8IdData.mData.CArray();
BfParser_SetCharIdData(mNativeBfParser, data, char8IdData.mLength);
}
public void SetCursorIdx(int cursorIdx)
{
BfParser_SetCursorIdx(mNativeBfParser, (int32)cursorIdx);
}
public void SetAutocomplete(int cursorIdx)
{
BfParser_SetAutocomplete(mNativeBfParser, (int32)cursorIdx);
}
public void SetIsClassifying()
{
BfParser_SetIsClassifying(mNativeBfParser);
}
public bool Parse(BfPassInstance passInstance, bool compatMode)
{
return BfParser_Parse(mNativeBfParser, passInstance.mNativeBfPassInstance, compatMode);
}
public bool Reduce(BfPassInstance passInstance)
{
return BfParser_Reduce(mNativeBfParser, passInstance.mNativeBfPassInstance);
}
public void Reformat(int formatStart, int formatEnd, out int32[] char8Mapping, String str)
{
int32* char8MappingPtr;
var stringPtr = BfParser_Format(mNativeBfParser, (int32)formatStart, (int32)formatEnd, out char8MappingPtr);
str.Append(stringPtr);
char8Mapping = new int32[str.Length];
for (int32 i = 0; i < char8Mapping.Count; i++)
char8Mapping[i] = char8MappingPtr[i];
}
public bool GetDebugExpressionAt(int cursorIdx, String outExpr)
{
var stringPtr = BfParser_GetDebugExpressionAt(mNativeBfParser, (int32)cursorIdx);
if (stringPtr == null)
return false;
outExpr.Append(stringPtr);
return true;
}
public bool BuildDefs(BfPassInstance bfPassInstance, BfResolvePassData resolvePassData, bool fullRefresh)
{
void* nativeResolvePassData = null;
if (resolvePassData != null)
nativeResolvePassData = resolvePassData.mNativeResolvePassData;
return BfParser_BuildDefs(mNativeBfParser, bfPassInstance.mNativeBfPassInstance, nativeResolvePassData, fullRefresh);
}
public void RemoveDefs()
{
BfParser_RemoveDefs(mNativeBfParser);
}
public void ClassifySource(EditWidgetContent.CharData[] char8Data, bool preserveFlags)
{
EditWidgetContent.CharData* char8DataPtr = char8Data.CArray();
BfParser_ClassifySource(mNativeBfParser, char8DataPtr, preserveFlags);
}
public void SetNextRevision(BfParser nextRevision)
{
BfParser_SetNextRevision(mNativeBfParser, nextRevision.mNativeBfParser);
}
public void GenerateAutoCompletionFrom(int32 srcPosition)
{
BfParser_GenerateAutoCompletionFrom(mNativeBfParser, srcPosition);
}
public BfResolvePassData CreateResolvePassData(ResolveType resolveType = ResolveType.Autocomplete)
{
var resolvePassData = new BfResolvePassData();
resolvePassData.mNativeResolvePassData = BfParser_CreateResolvePassData(mNativeBfParser, (int32)resolveType);
return resolvePassData;
}
public void ReformatInto(SourceEditWidget editWidget, int formatStart, int formatEnd, uint8 orFlags = 0)
{
var editWidgetContent = (SourceEditWidgetContent)editWidget.Content;
/*let origText = scope String();
editWidget.GetText(origText);
File.WriteAllText(@"c:\temp\orig.txt", origText);*/
int32[] char8Mapping;
String newText = scope String();
Reformat(formatStart, formatEnd, out char8Mapping, newText);
defer delete char8Mapping;
//File.WriteAllText(@"c:\temp\new.txt", newText);
SourceEditBatchHelper sourceEditBatchHelper = scope SourceEditBatchHelper(editWidget, "format");
int32 insertCount = 0;
int32 deleteCount = 0;
int32 insertChars = 0;
int32 deleteChars = 0;
int32 insertStartIdx = -1;
int32 expectedOldIdx = 0;
for (int32 i = 0; i < char8Mapping.Count; i++)
{
int32 oldIdx = (int32)char8Mapping[i];
if ((oldIdx != -1) && (insertStartIdx != -1))
{
// Finish inserting
editWidgetContent.CursorTextPos = insertStartIdx;
String insertString = scope String();
//newText.Substring(insertStartIdx, i - insertStartIdx, insertString);
insertString.Append(newText, insertStartIdx, i - insertStartIdx);
var insertTextAction = new EditWidgetContent.InsertTextAction(editWidgetContent, insertString, .None);
insertTextAction.mMoveCursor = false;
editWidgetContent.mData.mUndoManager.Add(insertTextAction);
editWidgetContent.PhysInsertAtCursor(insertString, false);
if (orFlags != 0)
{
for (int32 idx = insertStartIdx; idx < i; idx++)
editWidgetContent.mData.mText[idx].mDisplayFlags |= orFlags;
}
insertStartIdx = -1;
insertCount++;
insertChars += (int32)insertString.Length;
}
if (oldIdx == expectedOldIdx)
{
expectedOldIdx++;
continue;
}
else if (oldIdx == -1)
{
if (insertStartIdx == -1)
insertStartIdx = i;
}
else
{
Debug.Assert(oldIdx > expectedOldIdx); // This fails if we have the same ID occur multiple times, or we reorder nodes
if (oldIdx <= expectedOldIdx)
break; // Error - abort
int32 charsToDelete = oldIdx - expectedOldIdx;
editWidgetContent.CursorTextPos = i;
var deleteCharAction = new EditWidgetContent.DeleteCharAction(editWidgetContent, 0, charsToDelete);
deleteCharAction.mMoveCursor = false;
editWidgetContent.mData.mUndoManager.Add(deleteCharAction);
editWidgetContent.PhysDeleteChars(0, charsToDelete);
expectedOldIdx = oldIdx + 1;
deleteCount++;
deleteChars += charsToDelete;
}
}
editWidgetContent.ContentChanged();
Debug.WriteLine("Reformat {0} inserts, total of {1} chars. {2} deletes, total of {3} chars.", insertCount, insertChars, deleteCount, deleteChars);
sourceEditBatchHelper.Finish();
}
public void SetCompleteParse()
{
BfParser_SetCompleteParse(mNativeBfParser);
}
}
}

View file

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Beefy.utils;
using System.Diagnostics;
using System.Threading;
namespace IDE.Compiler
{
public class BfPassInstance
{
[StdCall, CLink]
static extern void BfPassInstance_Delete(void* bfSystem);
[StdCall, CLink]
static extern char8* BfPassInstance_PopOutString(void* bfSystem);
[StdCall, CLink]
static extern void BfPassInstance_SetClassifierPassId(void* bfResolvePassData, uint8 classifierPassId);
[StdCall, CLink]
static extern int32 BfPassInstance_GetErrorCount(void* mNativeResolvePassData);
[StdCall, CLink]
static extern char8* BfPassInstance_GetErrorData(void* mNativeResolvePassData, int32 errorIdx, out bool isWarning,
out bool isAfter, out bool isDeferred, out bool isWhileSpecializing,
out bool isPersistent, out int32 srcStart, out int32 srcEnd, out int32 moreInfoCount);
[StdCall, CLink]
static extern char8* BfPassInstance_Error_GetMoreInfoData(void* mNativeResolvePassData, int32 errorIdx, int32 moreInfoIdx, out char8* fileName, out int32 srcStart, out int32 srcEnd);
[StdCall, CLink]
static extern bool BfPassInstance_HadSignatureChanges(void* mNativeResolvePassData);
public class BfError
{
public bool mIsWarning;
public bool mIsAfter;
public bool mIsDeferred;
public bool mIsWhileSpecializing;
public bool mIsPersistent;
public String mError ~ delete _;
public int32 mSrcStart;
public int32 mSrcEnd;
public int32 mMoreInfoCount;
public bool mOwnsSpan;
public IdSpan mIdSpan ~ { if (mOwnsSpan) _.Dispose(); };
public int32 mErrorIdx = -1;
public String mFileName ~ delete _;
public List<BfError> mMoreInfo ~ DeleteContainerAndItems!(_);
}
static public List<BfPassInstance> sPassInstances = new List<BfPassInstance>() ~ delete _;
static Monitor sMonitor = new Monitor() ~ delete _;
static int32 sCurId;
public void* mNativeBfPassInstance;
public bool mDidCompile;
public bool mCompileSucceeded;
public bool mIsDisposed;
public bool mFailed;
public int32 mId = sCurId++;
internal String mDbgStr ~ delete _;
public this(void* nativePassInstance)
{
mNativeBfPassInstance = nativePassInstance;
using (sMonitor.Enter())
{
sPassInstances.Add(this);
}
//Debug.Assert(sPassInstances.Count <= 5);
Debug.Assert(sPassInstances.Count <= 4);
}
public ~this()
{
Debug.Assert(!mIsDisposed);
using (sMonitor.Enter())
{
sPassInstances.Remove(this);
}
mIsDisposed = true;
BfPassInstance_Delete(mNativeBfPassInstance);
mNativeBfPassInstance = null;
if (mFailed)
{
NOP!();
}
}
public bool PopOutString(String outStr)
{
char8* strVal = BfPassInstance_PopOutString(mNativeBfPassInstance);
if (strVal == null)
return false;
outStr.Append(strVal);
return true;
}
public void SetClassifierPassId(uint8 classifierPassId)
{
BfPassInstance_SetClassifierPassId(mNativeBfPassInstance, classifierPassId);
}
public int32 GetErrorCount()
{
return BfPassInstance_GetErrorCount(mNativeBfPassInstance);
}
public void GetErrorData(int32 errorIdx, BfError bfError)
{
Debug.Assert(bfError.mError == null);
bfError.mErrorIdx = errorIdx;
bfError.mError = new String(BfPassInstance_GetErrorData(mNativeBfPassInstance, errorIdx, out bfError.mIsWarning, out bfError.mIsAfter, out bfError.mIsDeferred,
out bfError.mIsWhileSpecializing, out bfError.mIsPersistent, out bfError.mSrcStart, out bfError.mSrcEnd, out bfError.mMoreInfoCount));
}
public void GetMoreInfoErrorData(int32 errorIdx, int32 moreInfoIdx, BfError bfError)
{
char8* fileName = null;
char8* errorStr = BfPassInstance_Error_GetMoreInfoData(mNativeBfPassInstance, errorIdx, moreInfoIdx, out fileName, out bfError.mSrcStart, out bfError.mSrcEnd);
Debug.Assert(bfError.mFileName == null);
if (fileName != null)
bfError.mFileName = new String(fileName);
if (bfError.mError == null)
bfError.mError = new String(errorStr);
else
bfError.mError.Append(errorStr);
}
public bool HadSignatureChanges()
{
return BfPassInstance_HadSignatureChanges(mNativeBfPassInstance);
}
}
}

View file

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace IDE.Compiler
{
public class BfProject
{
[StdCall, CLink]
extern static void BfProject_Delete(void* nativeBfProject);
[StdCall, CLink]
extern static void BfProject_ClearDependencies(void* nativeBfProject);
[StdCall, CLink]
extern static void BfProject_AddDependency(void* nativeBfProject, void* nativeDepProject);
[StdCall, CLink]
extern static void BfProject_SetDisabled(void* nativeBfProject, bool disabled);
[StdCall, CLink]
extern static void BfProject_SetOptions(void* nativeBfProject, int32 targetType, char8* startupObject, char8* preprocessorMacros,
int32 optLevel, int32 ltoType, bool mergeFunctions, bool combineLoads, bool vectorizeLoops, bool vectorizeSLP);
public void* mNativeBfProject;
public bool mDisabled;
public void Dispose()
{
BfProject_Delete(mNativeBfProject);
}
public void ClearDependencies()
{
BfProject_ClearDependencies(mNativeBfProject);
}
public void AddDependency(BfProject depProject)
{
BfProject_AddDependency(mNativeBfProject, depProject.mNativeBfProject);
}
public void SetDisabled(bool disabled)
{
mDisabled = disabled;
BfProject_SetDisabled(mNativeBfProject, disabled);
}
public void SetOptions(Project.TargetType targetType, String startupObject, List<String> preprocessorMacros,
BuildOptions.BfOptimizationLevel optLevel, BuildOptions.LTOType ltoType, bool mergeFunctions, bool combineLoads, bool vectorizeLoops, bool vectorizeSLP)
{
String macrosStr = scope String();
macrosStr.Join("\n", preprocessorMacros.GetEnumerator());
BfProject_SetOptions(mNativeBfProject, (int32)targetType, startupObject, macrosStr,
(int32)optLevel, (int32)ltoType, mergeFunctions, combineLoads, vectorizeLoops, vectorizeSLP);
}
}
}

View file

@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using IDE.ui;
using System.IO;
namespace IDE.Compiler
{
public class BfResolveHelper
{
class DeferredReparseEntry
{
public int32 mWaitTicks;
public String mFilePath ~ delete _;
public SourceViewPanel mExludeSourceViewPanel;
}
List<DeferredReparseEntry> mDeferredReparses = new List<DeferredReparseEntry>() ~ DeleteContainerAndItems!(_);
int32 mVisibleViewRefreshWaitTicks;
SourceViewPanel mVisibleViewRefreshExcludeSourceView;
public void SourceViewPanelClosed(SourceViewPanel sourceViewPanel)
{
if (mVisibleViewRefreshExcludeSourceView == sourceViewPanel)
mVisibleViewRefreshExcludeSourceView = null;
for (var entry in mDeferredReparses)
{
if (entry.mExludeSourceViewPanel == sourceViewPanel)
entry.mExludeSourceViewPanel = null;
}
}
public void ProjectSourceRemoved(ProjectSource projectSource)
{
// Don't need to do anything
}
public void DeferRefreshVisibleViews(SourceViewPanel sourceViewPanel)
{
if (mVisibleViewRefreshWaitTicks == 0)
{
mVisibleViewRefreshWaitTicks = 30;
mVisibleViewRefreshExcludeSourceView = sourceViewPanel;
}
else
{
mVisibleViewRefreshWaitTicks = 30;
if (mVisibleViewRefreshExcludeSourceView != sourceViewPanel)
{
// We already had another soruceView that queued up a refresh
// so remove the exclusion
mVisibleViewRefreshExcludeSourceView = null;
}
}
}
public void DeferReparse(String fileName, SourceViewPanel excludeSourceVewPanel)
{
DeferRefreshVisibleViews(excludeSourceVewPanel);
for (var entry in mDeferredReparses)
{
if (Path.Equals(entry.mFilePath, fileName))
{
if (entry.mExludeSourceViewPanel != excludeSourceVewPanel)
entry.mExludeSourceViewPanel = null; // Reparse them all
entry.mWaitTicks = 30;
return;
}
}
var newEntry = new DeferredReparseEntry();
newEntry.mFilePath = new String(fileName);
newEntry.mExludeSourceViewPanel = excludeSourceVewPanel;
newEntry.mWaitTicks = 30;
mDeferredReparses.Add(newEntry);
}
public void Update()
{
var app = IDEApp.sApp;
if ((mVisibleViewRefreshWaitTicks > 0) && (--mVisibleViewRefreshWaitTicks == 0))
{
if (!app.mBfResolveCompiler.IsPerformingBackgroundOperation())
{
app.RefreshVisibleViews(mVisibleViewRefreshExcludeSourceView);
}
else
{
// Try again next tick
mVisibleViewRefreshWaitTicks = 1;
}
}
if (mDeferredReparses.Count > 0)
{
var entry = mDeferredReparses[0];
if ((--entry.mWaitTicks <= 0) && (!app.mBfResolveCompiler.IsPerformingBackgroundOperation()))
{
bool needsResolveAll = false;
app.mWorkspace.WithProjectItems(scope [&] (projectItem) =>
{
var projectSource = projectItem as ProjectSource;
if ((projectSource != null) &&
((entry.mExludeSourceViewPanel == null) || (projectSource != entry.mExludeSourceViewPanel.mProjectSource)))
{
var fullPath = scope String();
projectSource.GetFullImportPath(fullPath);
if (Path.Equals(fullPath, entry.mFilePath))
{
app.mBfResolveCompiler.QueueProjectSource(projectSource);
needsResolveAll = true;
DeferRefreshVisibleViews(entry.mExludeSourceViewPanel);
}
}
});
if (needsResolveAll)
app.mBfResolveCompiler.QueueDeferredResolveAll();
mDeferredReparses.RemoveAt(0);
delete entry;
}
}
}
}
}

View file

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace IDE.Compiler
{
public class BfResolvePassData
{
[StdCall, CLink]
static extern void BfResolvePassData_Delete(void* bfResolvePassData);
[StdCall, CLink]
static extern void BfResolvePassData_SetLocalId(void* bfResolvePassData, int32 localId);
[StdCall, CLink]
static extern void BfResolvePassData_SetTypeGenericParamIdx(void* resolvePassData, int typeGenericParamIdx);
[StdCall, CLink]
static extern void BfResolvePassData_SetMethodGenericParamIdx(void* resolvePassData, int typeGenericParamIdx);
[StdCall, CLink]
static extern void BfResolvePassData_SetSymbolReferenceTypeDef(void* bfResolvePassData, char8* replaceStr);
[StdCall, CLink]
static extern void BfResolvePassData_SetSymbolReferenceFieldIdx(void* bfResolvePassData, int32 fieldIdx);
[StdCall, CLink]
static extern void BfResolvePassData_SetSymbolReferenceMethodIdx(void* bfResolvePassData, int32 methodIdx);
[StdCall, CLink]
static extern void BfResolvePassData_SetSymbolReferencePropertyIdx(void* bfResolvePassData, int32 propertyIdx);
[StdCall, CLink]
static extern void BfResolvePassData_SetDocumentationRequest(void* bfResolvePassData, char8* entryName);
//
//[StdCall, CLink]
//static extern void* BfParser_CreateResolvePassData(void* bfSystem, int32 resolveType);
public void* mNativeResolvePassData;
public ~this()
{
BfResolvePassData_Delete(mNativeResolvePassData);
}
public void SetLocalId(int32 localId)
{
BfResolvePassData_SetLocalId(mNativeResolvePassData, localId);
}
public void SetTypeGenericParamIdx(int32 genericParamIdx)
{
BfResolvePassData_SetTypeGenericParamIdx(mNativeResolvePassData, genericParamIdx);
}
public void SetMethodGenericParamIdx(int32 genericParamIdx)
{
BfResolvePassData_SetMethodGenericParamIdx(mNativeResolvePassData, genericParamIdx);
}
public void SetSymbolReferenceTypeDef(String typeDefName)
{
BfResolvePassData_SetSymbolReferenceTypeDef(mNativeResolvePassData, typeDefName);
}
public void SetSymbolReferenceFieldIdx(int32 fieldIdx)
{
BfResolvePassData_SetSymbolReferenceFieldIdx(mNativeResolvePassData, fieldIdx);
}
public void SetSymbolReferenceMethodIdx(int32 methodIdx)
{
BfResolvePassData_SetSymbolReferenceMethodIdx(mNativeResolvePassData, methodIdx);
}
public void SetSymbolReferencePropertyIdx(int32 propertyIdx)
{
BfResolvePassData_SetSymbolReferencePropertyIdx(mNativeResolvePassData, propertyIdx);
}
public void SetDocumentationRequest(String entryName)
{
BfResolvePassData_SetDocumentationRequest(mNativeResolvePassData, entryName);
}
public static BfResolvePassData Create(ResolveType resolveType = ResolveType.Autocomplete)
{
var resolvePassData = new BfResolvePassData();
resolvePassData.mNativeResolvePassData = BfParser.[Friend]BfParser_CreateResolvePassData(null, (int32)resolveType);
return resolvePassData;
}
}
}

View file

@ -0,0 +1,365 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace IDE.Compiler
{
public class BfSystem
{
[StdCall, CLink]
static extern void BfSystem_CheckLock(void* bfSystem);
[StdCall, CLink]
static extern void* BfSystem_Create();
[StdCall, CLink]
static extern void BfSystem_Delete(void* bfSystem);
[StdCall, CLink]
static extern void BfSystem_ReportMemory(void* bfSystem);
[StdCall, CLink]
static extern void BfSystem_Update(void* bfSystem);
[StdCall, CLink]
static extern void* BfSystem_CreatePassInstance(void* bfSystem);
[StdCall, CLink]
static extern char8* BfSystem_GetNamespaceSearch(void* bfSystem, char8* typeName, void* project);
[StdCall, CLink]
static extern void* BfSystem_CreateProject(void* bfSystem, char8* projectName);
[StdCall, CLink]
static extern void BfSystem_ClearTypeOptions(void* bfSystem);
[StdCall, CLink]
static extern void BfSystem_AddTypeOptions(void* bfSystem, char8* filter, int32 simdSetting, int32 optimizationLevel, int32 emitDebugInfo, int32 runtimeChecks,
int32 initLocalVariables, int32 emitDynamicCastCheck, int32 emitObjectAccessCheck, int32 allocStackTraceDepth);
[StdCall, CLink]
static extern void* BfSystem_CreateParser(void* bfSystem, void* bfProject);
[StdCall, CLink]
static extern void* BfSystem_CreateCompiler(void* bfSystem, bool isResolveOnly = false);
[StdCall, CLink]
static extern void* BfSystem_RemoveDeletedParsers(void* bfSystem);
[StdCall, CLink]
static extern void* BfSystem_RemoveOldParsers(void* bfSystem);
[StdCall, CLink]
static extern void* BfSystem_RemoveOldData(void* bfSystem);
[StdCall, CLink]
static extern void* BfSystem_NotifyWillRequestLock(void* bfSystem, int32 priority);
[StdCall, CLink]
static extern void* BfSystem_Lock(void* bfSystem, int32 priority);
[StdCall, CLink]
extern static void BfSystem_PerfZoneStart(char8* name);
[StdCall, CLink]
extern static void BfSystem_PerfZoneEnd();
[StdCall, CLink]
static extern void* BfSystem_Unlock(void* bfSystem);
[StdCall, CLink]
extern static void BfSystem_StartTiming();
[StdCall, CLink]
extern static void BfSystem_StopTiming();
[StdCall, CLink]
extern static void BfSystem_DbgPrintTimings();
public void* mNativeBfSystem;
public bool mIsTiming;
public Monitor mMonitor = new Monitor() ~ delete _;
public Dictionary<ProjectSource, BfParser> mParserMap = new Dictionary<ProjectSource, BfParser>() ~ delete _;
public Dictionary<Project, BfProject> mProjectMap = new Dictionary<Project, BfProject>() ~ delete _;
public this()
{
mNativeBfSystem = BfSystem_Create();
}
public ~this()
{
for (var parser in mParserMap.Values)
delete parser;
for (var bfProject in mProjectMap.Values)
delete bfProject;
BfSystem_Delete(mNativeBfSystem);
}
public void CheckLock()
{
BfSystem_CheckLock(mNativeBfSystem);
}
public void Update()
{
BfSystem_Update(mNativeBfSystem);
}
public void ReportMemory()
{
BfSystem_ReportMemory(mNativeBfSystem);
}
public void AddProject(Project project)
{
using (mMonitor.Enter())
{
var bfProject = CreateProject(project.mProjectName);
mProjectMap[project] = bfProject;
}
}
public BfProject GetBfProject(Project project)
{
using (mMonitor.Enter())
{
return mProjectMap[project];
}
}
public void RemoveBfProject(Project project)
{
using (mMonitor.Enter())
{
mProjectMap.Remove(project);
}
}
public BfPassInstance CreatePassInstance(String dbgStr = null)
{
void* nativePassInstance = BfSystem_CreatePassInstance(mNativeBfSystem);
BfPassInstance passInstance = new BfPassInstance(nativePassInstance);
if (dbgStr != null)
passInstance.mDbgStr = new String(dbgStr);
return passInstance;
}
public BfParser CreateEmptyParser(BfProject bfProject)
{
void* nativeBfProject = (bfProject == null) ? null : bfProject.mNativeBfProject;
void* nativeBfParser = BfSystem_CreateParser(mNativeBfSystem, nativeBfProject);
BfParser parser = new BfParser(nativeBfParser);
parser.mSystem = this;
return parser;
}
public void GetNamespaceSearch(String typeName, String outNamespaceSearch, BfProject project)
{
char8* namespaceSearch = BfSystem_GetNamespaceSearch(mNativeBfSystem, typeName, project.mNativeBfProject);
if (namespaceSearch != null)
outNamespaceSearch.Append(namespaceSearch);
}
public BfProject CreateProject(String projectName)
{
BfProject project = new BfProject();
project.mNativeBfProject = BfSystem_CreateProject(mNativeBfSystem, projectName);
return project;
}
/*public bool HasParser(string fileName)
{
lock (this)
{
return mParserMap.ContainsKey(fileName);
}
}*/
public BfParser CreateParser(ProjectSource projectSource, bool useMap = true)
{
using (mMonitor.Enter())
{
BfParser parser;
if (!useMap)
{
parser = CreateEmptyParser(mProjectMap[projectSource.mProject]);
parser.mProjectSource = projectSource;
parser.mFileName = new String();
projectSource.GetFullImportPath(parser.mFileName);
return parser;
}
BfParser prevParser;
mParserMap.TryGetValue(projectSource, out prevParser);
parser = CreateEmptyParser(mProjectMap[projectSource.mProject]);
parser.mSystem = this;
parser.mProjectSource = projectSource;
parser.mFileName = new String();
projectSource.GetFullImportPath(parser.mFileName);
mParserMap[projectSource] = parser;
if (prevParser != null)
{
prevParser.SetNextRevision(parser);
prevParser.Detach();
delete prevParser;
}
return parser;
}
}
public BfParser CreateNewParserRevision(BfParser prevParser)
{
using (mMonitor.Enter())
{
BfParser parser = CreateEmptyParser(mProjectMap[prevParser.mProjectSource.mProject]);
parser.mFileName = new String(prevParser.mFileName);
parser.mProjectSource = prevParser.mProjectSource;
mParserMap[parser.mProjectSource] = parser;
if (prevParser != null)
{
prevParser.SetNextRevision(parser);
prevParser.Detach();
delete prevParser;
}
return parser;
}
}
public void FileRenamed(ProjectSource projectSource, String oldFileName, String newFileName)
{
using (mMonitor.Enter())
{
BfParser prevParser;
if (mParserMap.TryGetValue(projectSource, out prevParser))
{
prevParser.mFileName.Set(newFileName);
}
}
}
public BfParser FileRemoved(ProjectSource projectSource)
{
using (mMonitor.Enter())
{
BfParser prevParser = null;
if (mParserMap.TryGetValue(projectSource, out prevParser))
{
//DeleteParser(prevParser);
mParserMap.Remove(projectSource);
}
return prevParser;
}
}
public BfParser FindParser(ProjectSource projectSource)
{
using (mMonitor.Enter())
{
BfParser prevParser;
mParserMap.TryGetValue(projectSource, out prevParser);
return prevParser;
}
}
public BfCompiler CreateCompiler(bool isResolveOnly)
{
void* nativeBfCompiler = BfSystem_CreateCompiler(mNativeBfSystem, isResolveOnly);
var bfCompiler = new BfCompiler(nativeBfCompiler);
bfCompiler.mIsResolveOnly = isResolveOnly;
bfCompiler.mBfSystem = this;
return bfCompiler;
}
public void RemoveDeletedParsers()
{
BfSystem_RemoveDeletedParsers(mNativeBfSystem);
}
public void RemoveOldParsers()
{
BfSystem_RemoveOldParsers(mNativeBfSystem);
}
public void RemoveOldData()
{
BfSystem_RemoveOldData(mNativeBfSystem);
}
public void NotifyWillRequestLock(int32 priority)
{
BfSystem_NotifyWillRequestLock(mNativeBfSystem, priority);
}
public void Lock(int32 priority)
{
BfSystem_Lock(mNativeBfSystem, priority);
}
public void Unlock()
{
BfSystem_Unlock(mNativeBfSystem);
}
public void StartTiming()
{
mIsTiming = true;
BfSystem_StartTiming();
}
public void PerfZoneStart(String name)
{
BfSystem_PerfZoneStart(name);
}
public void PerfZoneEnd()
{
BfSystem_PerfZoneEnd();
}
public void StopTiming()
{
mIsTiming = false;
BfSystem_StopTiming();
}
public void DbgPrintTimings()
{
BfSystem_DbgPrintTimings();
}
public void ClearTypeOptions()
{
BfSystem_ClearTypeOptions(mNativeBfSystem);
}
public void AddTypeOptions(String filter, BuildOptions.SIMDSetting? simdSetting, BuildOptions.BfOptimizationLevel? optimizationLevel, BuildOptions.EmitDebugInfo? emitDebugInfo, bool? runtimeChecks,
bool? initLocalVariables, bool? emitDynamicCastCheck, bool? emitObjectAccessCheck, int32? allocStackTraceDepth)
{
int32 simdSettingInt = (simdSetting == null) ? -1 : (int32)simdSetting.Value;
int32 optimizationLevelInt = (optimizationLevel == null) ? -1 : (int32)optimizationLevel.Value;
int32 emitDebugInfoInt = (emitDebugInfo == null) ? -1 : (int32)emitDebugInfo.Value;
int32 runtimeChecksInt = (runtimeChecks == null) ? -1 : runtimeChecks.Value ? 1 : 0;
int32 initLocalVariablesInt = (initLocalVariables == null) ? -1 : initLocalVariables.Value ? 1 : 0;
int32 emitDynamicCastCheckInt = (emitDynamicCastCheck == null) ? -1 : emitDynamicCastCheck.Value ? 1 : 0;
int32 emitObjectAccessCheckInt = (emitObjectAccessCheck == null) ? -1 : emitObjectAccessCheck.Value ? 1 : 0;
int32 allocStackTraceDepthInt = (allocStackTraceDepth == null) ? -1 : allocStackTraceDepth.Value;
BfSystem_AddTypeOptions(mNativeBfSystem, filter, simdSettingInt, optimizationLevelInt, emitDebugInfoInt, runtimeChecksInt,
initLocalVariablesInt, emitDynamicCastCheckInt, emitObjectAccessCheckInt, allocStackTraceDepthInt);
}
public void AddTypeOptions(DistinctBuildOptions typeOption)
{
AddTypeOptions(typeOption.mFilter, typeOption.mBfSIMDSetting, typeOption.mBfOptimizationLevel, typeOption.mEmitDebugInfo, typeOption.mRuntimeChecks,
typeOption.mInitLocalVariables, typeOption.mEmitDynamicCastCheck, typeOption.mEmitObjectAccessCheck, typeOption.mAllocStackTraceDepth);
}
}
}

View file

@ -0,0 +1,210 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using Beefy.utils;
using Beefy;
using System.IO;
namespace IDE.Compiler
{
public abstract class CompilerBase : CommandQueueManager
{
public int32 mResolveAllWait;
protected List<String> mQueuedOutput = new List<String>() ~ DeleteContainerAndItems!(_);
public bool mWantsActiveViewRefresh;
public volatile int32 mThreadYieldCount = 0; // Whether our thread wants to be yielded to, and for how many ticks
protected class ResolveAllCommand : Command
{
}
protected class ProjectSourceRemovedCommand : Command
{
public ProjectSource mProjectSource;
public ~this()
{
mProjectSource.ReleaseRef();
}
}
protected class ProjectSourceCommand : Command
{
public ProjectSource mProjectSource;
public IdSpan mSourceCharIdData ~ _.Dispose();
public String mSourceString ~ delete _;
}
protected class CompileCommand : Command
{
public String mOutputDirectory ~ delete _;
}
public void QueueCompile(String outputDirectory)
{
CompileCommand command = new CompileCommand();
command.mOutputDirectory = new String(outputDirectory);
QueueCommand(command);
}
public void QueueDeferredResolveAll()
{
/*if (gApp.mMainWindow.IsKeyDown(.Control))
{
NOP!();
}*/
mResolveAllWait = 2;
}
public virtual void QueueProjectSource(ProjectSource projectSource)
{
ProjectSourceCommand command = new ProjectSourceCommand();
command.mProjectSource = projectSource;
command.mSourceString = new String();
IDEApp.sApp.FindProjectSourceContent(projectSource, out command.mSourceCharIdData, false, command.mSourceString);
if (gApp.mBfBuildCompiler == this)
{
if (gApp.mDbgVersionedCompileDir != null)
{
String fileName = scope .();
projectSource.GetFullImportPath(fileName);
String baseSrcDir = scope .();
baseSrcDir.Append(projectSource.mProject.mProjectDir);
baseSrcDir.Append(@"\src\");
if (fileName.StartsWith(baseSrcDir, .OrdinalIgnoreCase))
{
fileName.Remove(0, baseSrcDir.Length - 1);
fileName.Insert(0, projectSource.mProject.mProjectName);
}
//Console.WriteLine("Hey!");
fileName.Replace('\\', '_');
fileName.Replace('/', '_');
String path = scope .();
path.Append(gApp.mDbgVersionedCompileDir);
path.Append(fileName);
//Utils.WriteTextFile(path, command.mSourceString);
var filePath = scope String();
projectSource.GetFullImportPath(filePath);
String contents = scope .();
contents.AppendF("//@{}|{}\n", filePath, File.GetLastWriteTime(filePath).GetValueOrDefault().ToFileTime());
contents.Append(command.mSourceString);
File.WriteAllText(path, contents);
}
}
QueueCommand(command);
}
public virtual void ClearQueuedProjectSource()
{
using (mMonitor.Enter())
{
// Don't remove the head of the queue because we may already be processing it
for (int32 i = 1; i < mCommandQueue.Count; i++)
{
if (mCommandQueue[i] is ProjectSourceCommand)
{
mCommandQueue.RemoveAt(i);
i--;
}
}
}
}
public void QueueProjectSourceRemoved(ProjectSource projectSource)
{
ProjectSourceRemovedCommand command = new ProjectSourceRemovedCommand();
command.mProjectSource = projectSource;
projectSource.AddRef();
QueueCommand(command);
}
public bool HasResolvedAll()
{
return (!HasQueuedCommands()) && (mResolveAllWait == 0);
}
public void QueueResolveCommand()
{
/*if (gApp.mMainWindow.IsKeyDown(.Control))
{
NOP!();
}*/
ResolveAllCommand command = new ResolveAllCommand();
QueueCommand(command);
}
public override void ProcessQueue()
{
mThreadYieldCount = 0;
DoProcessQueue();
}
public override void Update()
{
if (!ThreadRunning)
{
CheckThreadDone();
if (mWantsActiveViewRefresh)
{
IDEApp.sApp.RefreshVisibleViews();
mWantsActiveViewRefresh = false;
}
if (mThreadYieldCount > 0)
{
mThreadYieldCount--;
}
else if (mAllowThreadStart)
{
if (mResolveAllWait > 0)
{
if (--mResolveAllWait == 0)
{
QueueResolveCommand();
}
}
if (mCommandQueue.Count > 0)
{
StartQueueProcessThread();
}
}
}
}
public bool PopMessage(String outMessage)
{
using (mMonitor.Enter())
{
if (mQueuedOutput.Count > 0)
{
String msg = mQueuedOutput[0];
mQueuedOutput.RemoveAt(0);
msg.MoveTo(outMessage);
delete msg;
return true;
}
}
return false;
}
public void ClearMessages()
{
using (mMonitor.Enter())
{
ClearAndDeleteItems(mQueuedOutput);
}
}
}
}

203
IDE/src/CompositeFile.bf Normal file
View file

@ -0,0 +1,203 @@
using System.Collections.Generic;
using System;
using Beefy;
using System.IO;
using System.Diagnostics;
using System.Threading;
namespace IDE
{
class CompositeFile
{
public static String sMainFileName = "@main.bf";
public Monitor mMonitor = new .() ~ delete _;
static String sVersionStr = "///@singleFileVersion ";
static String sSectionStr = "///@embed ";
public Dictionary<String, String> mData = new .() ~ DeleteDictionyAndKeysAndItems!(_);
public String mFilePath ~ delete _;
public bool mPendingSave;
public bool mHasChanges;
public this(StringView filePath)
{
Debug.Assert(mFilePath == null);
mFilePath = new String(filePath);
}
public ~this()
{
if (mHasChanges)
Save();
}
public bool HasUnsavedChanges
{
get
{
return mHasChanges;
}
}
public bool HasPendingSave
{
get
{
return mPendingSave;
}
}
public StringView FilePath
{
get
{
return mFilePath;
}
}
public bool IsIncluded(StringView name)
{
return name == sMainFileName;
}
public Result<void> Load()
{
String source = scope String();
if (File.ReadAllText(mFilePath, source, false) case .Err)
return .Err;
bool isMain = true;
String embedName = scope .(sMainFileName);
String content = scope .();
for (let line in source.Split('\n'))
{
if (line.StartsWith(sSectionStr))
{
Set(embedName, content);
embedName.Clear();
content.Clear();
embedName.Append(line, sSectionStr.Length);
isMain = false;
}
else if (line.StartsWith(sVersionStr))
{
// Ignore
int version = int.Parse(StringView(line, sVersionStr.Length)).GetValueOrDefault();
if (version != 1)
{
gApp.OutputLineSmart("ERROR: File '{0}' specifies invalid file version '{1}'. Beef upgrade required?", mFilePath, version);
return .Err;
}
}
else if (isMain)
{
if (!content.IsEmpty)
content.Append("\n");
content.Append(line);
}
else if (line.StartsWith("/// "))
{
if (!content.IsEmpty)
content.Append("\n");
content.Append(line, 4);
}
}
Set(embedName, content);
mHasChanges = false;
mPendingSave = false;
return .Ok;
}
public bool Get(StringView name, String outData)
{
using (mMonitor.Enter())
{
if (mData.TryGetValue(scope String()..Append(name), var value))
{
outData.Append(value);
return true;
}
return false;
}
}
public void Set(StringView name, StringView data)
{
using (mMonitor.Enter())
{
bool added = mData.TryAdd(scope String()..Append(name), var keyPtr, var valuePtr);
if (added)
{
mHasChanges = true;
mPendingSave = true;
*keyPtr = new String(name);
*valuePtr = new String(data);
}
else
{
if (*valuePtr != data)
{
mHasChanges = true;
mPendingSave = true;
(*valuePtr).Set(data);
}
}
}
}
public bool Save()
{
using (mMonitor.Enter())
{
mPendingSave = false;
if (!mHasChanges)
return true;
String str = scope String();
void Add(StringView name)
{
String sectionStr = scope String();
Get(name, sectionStr);
if (name == sMainFileName)
{
for (let line in sectionStr.Split('\n'))
{
if (@line.Pos != 0)
str.Append("\n");
str.Append(line);
}
return;
}
if (!sectionStr.IsEmpty)
{
str.Append("\n");
str.Append(sSectionStr);
str.Append(name);
str.Append("\n");
for (let line in sectionStr.Split('\n'))
{
str.Append("/// ");
str.Append(line);
str.Append("\n");
}
}
}
Add(sMainFileName);
str.Append("\n", sVersionStr, "1\n");
Add("Workspace");
Add("Project");
if (!gApp.SafeWriteTextFile(mFilePath, str))
return false;
mHasChanges = true;
}
return true;
}
}
}

View file

@ -0,0 +1,502 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Beefy.gfx;
using Beefy.theme.dark;
using System.IO;
namespace IDE.Debugger
{
public class Breakpoint : TrackedTextElement
{
[Reflect]
public enum HitCountBreakKind
{
None,
Equals,
GreaterEquals,
MultipleOf
};
[StdCall, CLink]
static extern void Breakpoint_Delete(void* nativeBreakpoint);
[StdCall, CLink]
static extern int32 Breakpoint_GetPendingHotBindIdx(void* nativeBreakpoint);
[StdCall, CLink]
static extern void Breakpoint_HotBindBreakpoint(void* breakpoint, int32 lineNum, int32 hotIdx);
[StdCall, CLink]
static extern int Breakpoint_GetAddress(void* nativeBreakpoint, out void* linkedSibling);
[StdCall, CLink]
static extern bool Breakpoint_SetCondition(void* nativeBreakpoint, char8* condition);
[StdCall, CLink]
static extern bool Breakpoint_SetLogging(void* nativeBreakpoint, char8* logging, bool breakAfterLogging);
[StdCall, CLink]
static extern bool Breakpoint_IsMemoryBreakpointBound(void* nativeBreakpoint);
[StdCall, CLink]
static extern int32 Breakpoint_GetLineNum(void* nativeBreakpoint);
[StdCall, CLink]
static extern void Breakpoint_Move(void* nativeBreakpoint, int32 wantLineNum, int32 wantColumn, bool rebindNow);
[StdCall, CLink]
static extern void Breakpoint_MoveMemoryBreakpoint(void* nativeBreakpoint, int addr, int32 byteCount);
[StdCall, CLink]
static extern void Breakpoint_Disable(void* nativeBreakpoint);
[StdCall, CLink]
static extern void* Debugger_CreateBreakpoint(char8* fileName, int32 wantLineNum, int32 wantColumn, int32 instrOffset);
[StdCall,CLink]
static extern void* Debugger_CreateSymbolBreakpoint(char8* symbolName);
[StdCall, CLink]
static extern void* Breakpoint_Check(void* nativeBreakpoint);
[StdCall, CLink]
static extern void Breakpoint_SetThreadId(void* nativeBreakpoint, int threadId);
[StdCall, CLink]
static extern int32 Breakpoint_GetHitCount(void* nativeBreakpoint);
[StdCall, CLink]
static extern int32 Breakpoint_ClearHitCount(void* nativeBreakpoint);
[StdCall, CLink]
static extern void Breakpoint_SetHitCountTarget(void* nativeBreakpoint, int hitCountTarget, HitCountBreakKind breakKind);
[StdCall, CLink]
static extern void* Debugger_GetActiveBreakpoint();
[StdCall, CLink]
internal static extern void* Debugger_CreateMemoryBreakpoint(int addr, int32 byteCount);
public void* mNativeBreakpoint;
public String mSymbol ~ delete _;
public bool mIsDisposed;
public int32 mInstrOffset;
public bool mAddressRequested;
public bool mIsMemoryBreakpoint;
public uint8 mByteCount;
public int mMemoryAddress;
public HitCountBreakKind mHitCountBreakKind;
public int mHitCountTarget;
public String mAddrType ~ delete _;
public String mMemoryWatchExpression ~ delete _;
public String mCondition ~ delete _;
public String mLogging ~ delete _;
public bool mBreakAfterLogging;
public int mThreadId = -1;
public bool mDisabled;
public bool mDeleteOnUnbind;
public Event<Action> mOnDelete;
internal ~this()
{
mOnDelete();
mIsDisposed = true;
DisposeNative();
}
void RehupBreakpointSettings()
{
if (!String.IsNullOrEmpty(mCondition))
SetCondition();
if (!String.IsNullOrEmpty(mLogging))
SetLogging();
if (mHitCountBreakKind != .None)
Breakpoint_SetHitCountTarget(mNativeBreakpoint, mHitCountTarget, mHitCountBreakKind);
if (mThreadId != -1)
Breakpoint_SetThreadId(mNativeBreakpoint, mThreadId);
}
public void CreateNative(bool bindNow = true)
{
//var debugger = IDEApp.sApp.mDebugger;
if (mNativeBreakpoint == null)
{
if (mIsMemoryBreakpoint)
{
// Wait for a 'rehup'
//mNativeBreakpoint = Debugger_CreateMemoryBreakpoint((void*)mMemoryAddress, mByteCount);
}
else if (mAddressRequested)
{
// Wait for a 'rehup'
//mNativeBreakpoint = Debugger_CreateAddressBreakpoint(mMemoryAddress);
}
else if (mFileName != null)
{
mNativeBreakpoint = Debugger_CreateBreakpoint(mFileName, mLineNum, mColumn, mInstrOffset);
RehupBreakpointSettings();
if (bindNow)
Breakpoint_Check(mNativeBreakpoint);
CheckBreakpointHotBinding();
}
else if (mSymbol != null)
{
mNativeBreakpoint = Debugger_CreateSymbolBreakpoint(mSymbol);
RehupBreakpointSettings();
if (bindNow)
Breakpoint_Check(mNativeBreakpoint);
CheckBreakpointHotBinding();
}
}
}
public override void Kill()
{
DisposeNative();
base.Kill();
}
public void DisposeNative()
{
if (mNativeBreakpoint != null)
{
Breakpoint_Delete(mNativeBreakpoint);
mNativeBreakpoint = null;
}
}
public bool IsBound()
{
if (mNativeBreakpoint == null)
return false;
void* linkedSibling;
if (mIsMemoryBreakpoint)
return Breakpoint_IsMemoryBreakpointBound(mNativeBreakpoint);
else
return Breakpoint_GetAddress(mNativeBreakpoint, out linkedSibling) != (int)0;
}
public bool IsActiveBreakpoint()
{
if (mNativeBreakpoint == null)
return false;
return mNativeBreakpoint == Debugger_GetActiveBreakpoint();
}
public int GetAddress(ref void* curBreakpoint)
{
if (curBreakpoint == null)
curBreakpoint = mNativeBreakpoint;
if (curBreakpoint == null)
return 0;
return Breakpoint_GetAddress(curBreakpoint, out curBreakpoint);
}
public bool ContainsAddress(int addr)
{
void* breakItr = mNativeBreakpoint;
while (true)
{
if (breakItr == null)
return false;
int breakAddr = Breakpoint_GetAddress(breakItr, out breakItr);
if (breakAddr == addr)
return true;
}
}
void SetCondition()
{
if (mNativeBreakpoint == null)
return;
if (String.IsNullOrWhiteSpace(mCondition))
{
Breakpoint_SetCondition(mNativeBreakpoint, "");
return;
}
String condition = scope .();
GetEvalStrWithSubject(mCondition, condition);
Breakpoint_SetCondition(mNativeBreakpoint, condition);
}
public void SetCondition(String condition)
{
String.NewOrSet!(mCondition, condition);
mCondition.Trim();
SetCondition();
if (mCondition.Length == 0)
{
delete mCondition;
mCondition = null;
}
}
public void SetThreadId(int threadId)
{
mThreadId = threadId;
if (mNativeBreakpoint != null)
Breakpoint_SetThreadId(mNativeBreakpoint, mThreadId);
}
void GetEvalStrWithSubject(String exprStr, String outStr)
{
if (mAddrType == null)
{
outStr.Append(exprStr);
return;
}
var enumerator = mAddrType.Split('\t');
int langVal = int.Parse(enumerator.GetNext().Get()).Get();
StringView addrVal = enumerator.GetNext().Get();
if (langVal == (.)DebugManager.Language.C)
outStr.Append("@C:");
else
outStr.Append("@Beef:");
outStr.Append(exprStr);
outStr.AppendF("\n({0}*)0x", addrVal);
mMemoryAddress.ToString(outStr, "X", null);
outStr.Append("L");
}
void SetLogging()
{
if (mNativeBreakpoint == null)
return;
if (String.IsNullOrWhiteSpace(mLogging))
{
Breakpoint_SetLogging(mNativeBreakpoint, "", false);
return;
}
String logging = scope .();
GetEvalStrWithSubject(mLogging, logging);
Breakpoint_SetLogging(mNativeBreakpoint, logging, mBreakAfterLogging);
}
public void SetLogging(String logging, bool breakAfterLogging)
{
String.NewOrSet!(mLogging, logging);
mLogging.Trim();
mBreakAfterLogging = breakAfterLogging;
SetLogging();
if (mLogging.Length == 0)
{
delete mLogging;
mLogging = null;
}
}
public void SetHitCountTarget(int hitCountTarget, HitCountBreakKind hitCountBreakKind)
{
mHitCountTarget = hitCountTarget;
mHitCountBreakKind = hitCountBreakKind;
if (mNativeBreakpoint != null)
Breakpoint_SetHitCountTarget(mNativeBreakpoint, hitCountTarget, hitCountBreakKind);
}
public bool HasNativeBreakpoint()
{
return mNativeBreakpoint != null;
}
public int32 GetLineNum()
{
/*if (mNativeBreakpoint == null)
return mLineNum;*/
if (mNativeBreakpoint == null)
return mLineNum;
int32 lineNum = Breakpoint_GetLineNum(mNativeBreakpoint);
if (lineNum != -1)
return lineNum;
return mLineNum;
}
public override void Move(int wantLineNum, int wantColumn)
{
//Breakpoint_Move(mNativeBreakpoint, wantLineNum, wantColumn);
mLineNum = (int32)wantLineNum;
mColumn = (int32)wantColumn;
}
public void MoveMemoryBreakpoint(int addr, int byteCount, String addrType)
{
mMemoryAddress = addr;
mByteCount = (uint8)byteCount;
if (addrType != null)
String.NewOrSet!(mAddrType, addrType);
if (mNativeBreakpoint == null)
{
mNativeBreakpoint = Debugger_CreateMemoryBreakpoint(addr, (.)byteCount);
RehupBreakpointSettings();
}
else
Breakpoint_MoveMemoryBreakpoint(mNativeBreakpoint, addr, (.)byteCount);
}
public void Rehup(bool rebindNow)
{
Breakpoint_Move(mNativeBreakpoint, mLineNum, mColumn, rebindNow);
CheckBreakpointHotBinding();
}
public void Disable()
{
if (mNativeBreakpoint != null)
{
//Breakpoint_Disable(mNativeBreakpoint);
Breakpoint_Delete(mNativeBreakpoint);
mNativeBreakpoint = null;
}
}
public void CheckBreakpointHotBinding()
{
if (mNativeBreakpoint == null)
return;
ProjectSource projectSource;
while (true)
{
int32 hotIdx = Breakpoint_GetPendingHotBindIdx(mNativeBreakpoint);
if (hotIdx == -1)
break;
projectSource = gApp.FindProjectSourceItem(mFileName);
if (projectSource == null)
break;
var editData = gApp.GetEditData(projectSource, true);
int char8Id = editData.mEditWidget.Content.GetSourceCharIdAtLineChar(mLineNum, mColumn);
if (char8Id == 0)
break;
int lineNum = mLineNum;
int column = mColumn;
if (!gApp.mWorkspace.GetProjectSourceCharIdPosition(projectSource, hotIdx, char8Id, ref lineNum, ref column))
lineNum = -1; // Don't bind
Breakpoint_HotBindBreakpoint(mNativeBreakpoint, (int32)lineNum, hotIdx);
}
}
public void Draw(Graphics g, bool isOldCompiledVersion)
{
uint32 color = Color.White;
bool isBreakEx = (mCondition != null) || (mLogging != null) || (mHitCountBreakKind != .None);
Image image = DarkTheme.sDarkTheme.GetImage(isBreakEx ? .RedDotEx : .RedDot);
Image threadImage = null;
if (this == gApp.mDebugger.mRunToCursorBreakpoint)
{
image = DarkTheme.sDarkTheme.GetImage(.RedDotRunToCursor);
}
else
{
if (mDisabled)
{
image = DarkTheme.sDarkTheme.GetImage(isBreakEx ? DarkTheme.ImageIdx.RedDotExDisabled : DarkTheme.ImageIdx.RedDotDisabled);
}
else if (!isOldCompiledVersion)
{
//color = (breakpoint.IsBound()) ? Color.White : 0x8080FFFF;
if ((!IsBound()) || (mThreadId == 0))
image = DarkTheme.sDarkTheme.GetImage(isBreakEx ? DarkTheme.ImageIdx.RedDotExUnbound : DarkTheme.ImageIdx.RedDotUnbound);
}
else
color = 0x8080FFFF;
if (mThreadId == -1)
{
// Nothing
}
else if (mThreadId == 0)
threadImage = DarkTheme.sDarkTheme.GetImage(.ThreadBreakpointUnbound);
else if ((!gApp.mDebugger.IsPaused()) || (mThreadId == gApp.mDebugger.GetActiveThread()))
threadImage = DarkTheme.sDarkTheme.GetImage(.ThreadBreakpointMatch);
else
threadImage = DarkTheme.sDarkTheme.GetImage(.ThreadBreakpointNoMatch);
}
using (g.PushColor(color))
{
g.Draw(image, 0, 0);
if (threadImage != null)
g.Draw(threadImage, GS!(-11), 0);
}
}
public int GetHitCount()
{
if (mNativeBreakpoint == null)
return 0;
return Breakpoint_GetHitCount(mNativeBreakpoint);
}
public void ClearHitCount()
{
if (mNativeBreakpoint == null)
return;
Breakpoint_ClearHitCount(mNativeBreakpoint);
}
public void ToString_Location(String str)
{
if (mFileName != null)
{
Path.GetFileName(mFileName, str);
str.AppendF(":{0}", mLineNum + 1);
if (mInstrOffset >= 0)
str.AppendF("+{0}", mInstrOffset);
}
else if (mAddressRequested)
{
void* curSubBreakpoint = null;
int addr = GetAddress(ref curSubBreakpoint);
str.AppendF("0x{0:X08}", addr);
}
else if (mIsMemoryBreakpoint)
{
void* curSubBreakpoint = null;
if (IsBound())
{
#unwarn
int addr = GetAddress(ref curSubBreakpoint);
str.AppendF("When '0x{0:X08}' ({1}) changes", mMemoryAddress, mMemoryWatchExpression);
}
else
{
str.AppendF("Unbound: When ({0}) changes", mMemoryWatchExpression);
}
}
else if (mSymbol != null)
{
str.Append(mSymbol);
}
else
{
NOP!();
}
}
public void ToString_HitCount(String str)
{
str.AppendF("{0}", GetHitCount());
switch (mHitCountBreakKind)
{
case .Equals: str.AppendF(", Break={0}", mHitCountTarget);
case .GreaterEquals: str.AppendF(", Break>={0}", mHitCountTarget);
case .MultipleOf: str.AppendF(", Break%{0}", mHitCountTarget);
default:
}
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using System.Runtime.InteropServices;
using IDE;
namespace Debugger
{
static class Callbacks
{
[StdCall, CLink]
static extern void Debugger_SetCallbacks(void* callback);
public static void Init()
{
Debugger_SetCallbacks(
((Delegate_MapLine)scope => MapHotLine).GetFuncPtr()
);
}
delegate void Delegate_MapLine(char8* fileName, int32 line, int32* outHotLines, int32 hotLinesCount);
static void MapHotLine(char8* fileName, int32 line, int32* outHotLines, int32 hotLinesCount)
{
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Beefy.utils;
namespace IDE.Debugger
{
class DbgProfiler
{
public int mIdx;
public bool mIsManual;
[StdCall, CLink]
static extern void* Profiler_Delete(void* nativeProfiler);
[StdCall, CLink]
static extern void Profiler_Stop(void* nativeProfiler);
[StdCall, CLink]
static extern void Profiler_Clear(void* nativeProfiler);
[StdCall, CLink]
static extern char8* Profiler_GetThreadList(void* nativeProfiler);
[StdCall, CLink]
static extern char8* Profiler_GetOverview(void* nativeProfiler);
[StdCall, CLink]
static extern bool Profiler_IsRunning(void* nativeProfiler);
[StdCall, CLink]
static extern char8* Profiler_GetCallTree(void* nativeProfiler, int32 threadId, bool reverse);
void* mNativeProfiler;
public bool IsSampling
{
get
{
return Profiler_IsRunning(mNativeProfiler);
}
}
public this(void* nativeProfiler)
{
mNativeProfiler = nativeProfiler;
}
public ~this()
{
Profiler_Delete(mNativeProfiler);
}
public void Stop()
{
Profiler_Stop(mNativeProfiler);
}
public void Clear()
{
Profiler_Clear(mNativeProfiler);
}
public class Overview
{
public int32 mRecordedTicks;
public int32 mEndedTicks = -1;
public String mTitle = new String() ~ delete _;
public String mDescription = new String() ~ delete _;
public int32 mSamplesPerSecond;
public int32 mTotalVirtualSamples;
public int32 mTotalActualSamples;
public bool IsSampling
{
get
{
return mEndedTicks == -1;
}
}
}
public void GetOverview(Overview overview)
{
char8* resultCStr = Profiler_GetOverview(mNativeProfiler);
String str = scope String();
str.Append(resultCStr);
var lineItr = str.Split('\n');
var dataItr = lineItr.GetNext().Get().Split('\t');
overview.mRecordedTicks = int32.Parse(dataItr.GetNext());
if (dataItr.GetNext() case .Ok(let sv))
overview.mEndedTicks = int32.Parse(sv);
dataItr = lineItr.GetNext().Get().Split('\t');
overview.mSamplesPerSecond = int32.Parse(dataItr.GetNext());
overview.mTotalVirtualSamples = int32.Parse(dataItr.GetNext());
overview.mTotalActualSamples = int32.Parse(dataItr.GetNext());
overview.mDescription.Append(str, lineItr.MatchPos + 1);
overview.mTitle.Append(lineItr.GetNext().Get());
}
public void GetThreadList(String result)
{
char8* resultCStr = Profiler_GetThreadList(mNativeProfiler);
result.Append(resultCStr);
}
public void GetCallTree(int32 threadId, String result, bool reverse)
{
char8* resultCStr = Profiler_GetCallTree(mNativeProfiler, threadId, reverse);
result.Append(resultCStr);
}
public void GetLabel(String label)
{
label.AppendF("{0}", mIdx);
var overview = scope DbgProfiler.Overview();
GetOverview(overview);
if (!overview.mTitle.IsEmpty)
label.AppendF(" - {0}", overview.mTitle);
else if (mIsManual)
label.AppendF(" - Manual");
else
label.AppendF(" - Program");
}
}
}

View file

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace IDE.Debugger
{
enum StepFilterKind : int32
{
Default,
Filtered,
NotFiltered
}
public class StepFilter
{
public String mFilter ~ delete _;
public void* mNativeStepFilter;
public bool mIsGlobal;
public StepFilterKind mKind;
[StdCall, CLink]
static extern void StepFilter_Delete(char8* filter);
public ~this()
{
StepFilter_Delete(mFilter);
}
}
}

117
IDE/src/FileEditData.bf Normal file
View file

@ -0,0 +1,117 @@
using IDE.ui;
using System;
using System.IO;
using Beefy.utils;
using System.Collections.Generic;
using System.Security.Cryptography;
namespace IDE
{
public enum LineEndingKind
{
Lf, // \n
CrLf, // \r\n
Cr, // \r
#if BF_PLATFORM_WINDOWS
Default = CrLf,
#else
Default = Lf,
#endif
}
public class FileEditData
{
public int mRefCount = 1;
public String mSavedContent ~ delete _;
public IdSpan mSavedCharIdData = IdSpan() ~ _.Dispose();
public List<ProjectSource> mProjectSources = new List<ProjectSource>() ~ delete _;
public Event<Action> mEditWidgetCreatedEvent ~ _.Dispose();
public LineEndingKind mLineEndingKind;
public SourceEditWidget mEditWidget;
public int32 mLastFileTextVersion;
public bool mOwnsEditWidget;
public String mFilePath ~ delete _;
public String mQueuedContent ~ delete _;
public bool mHadRefusedFileChange;
public bool mFileDeleted;
public SourceHash mLoadedHash;
public this()
{
}
public void SetSavedData(String savedContent, IdSpan savedIdSpan)
{
if (savedContent != null)
{
if (mSavedContent == null)
mSavedContent = new String();
mSavedContent.Set(savedContent);
}
else
{
delete mSavedContent;
mSavedContent = null;
}
mSavedCharIdData.Dispose();
mSavedCharIdData = savedIdSpan.Duplicate();
}
public bool HasTextChanged()
{
if (mEditWidget == null)
return false;
return mLastFileTextVersion != mEditWidget.Content.mData.mCurTextVersionId;
}
public bool Reload()
{
mHadRefusedFileChange = false;
if (mEditWidget == null)
{
if (mQueuedContent != null)
{
var span = IdSpan.GetDefault((int32)mQueuedContent.Length);
SetSavedData(mQueuedContent, span);
span.Dispose();
DeleteAndNullify!(mQueuedContent);
}
}
else
{
var editWidgetContent = (SourceEditWidgetContent)mEditWidget.mEditWidgetContent;
mFileDeleted = !editWidgetContent.Reload(mFilePath, mQueuedContent);
mLastFileTextVersion = mEditWidget.Content.mData.mCurTextVersionId;
}
return true;
}
public bool IsFileDeleted()
{
if (mFileDeleted) // Double check
mFileDeleted = !File.Exists(mFilePath);
return mFileDeleted;
}
public ~this()
{
if (mOwnsEditWidget)
delete mEditWidget;
}
public void Ref()
{
mRefCount++;
}
public void Deref()
{
if (--mRefCount == 0)
delete this;
}
}
}

610
IDE/src/FileWatcher.bf Normal file
View file

@ -0,0 +1,610 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Beefy;
using System.Threading;
using System.Diagnostics;
namespace IDE
{
public class FileWatcher
{
class WatcherEntry : RefCounted
{
// Either mFileSystemWatcher or mParentDirWatcher is set
public FileSystemWatcher mFileSystemWatcher ~ delete _;
public WatcherEntry mParentDirWatcher;
public String mDirectoryName;
public bool mIgnoreWrites;
public bool mHasSubDirDependencies;
public HashSet<String> mAmbiguousCreatePaths = new .() ~ DeleteContainerAndItems!(_);
}
class DepInfo
{
public List<Object> mDependentObjects = new List<Object>() ~ delete _;
public String mContent ~ delete _;
}
struct QueuedRefreshEntry
{
public WatcherEntry mWatcherEntry;
public int32 mDelay;
}
class QueuedFileChange
{
public String mFileName ~ delete _;
public String mNewFileName ~ delete _;
public WatcherChangeTypes mChangeType;
}
public class ChangeRecord
{
public String mPath ~ delete _;
public WatcherChangeTypes mChangeType;
}
// One watcher per directory
public static int32 sDbgFileCreateDelay;
Dictionary<String, WatcherEntry> mWatchers = new Dictionary<String, WatcherEntry>();
Dictionary<String, DepInfo> mWatchedFiles = new Dictionary<String, DepInfo>() ~ DeleteDictionyAndKeysAndItems!(_); // Including ref count
List<ChangeRecord> mChangeList = new .() ~ DeleteContainerAndItems!(_);
Dictionary<String, ChangeRecord> mChangeMap = new .() ~ delete _;
List<Object> mDependencyChangeList = new List<Object>() ~ delete _;
List<QueuedRefreshEntry> mQueuedRefreshWatcherEntries = new List<QueuedRefreshEntry>() ~ delete _;
public Monitor mMonitor = new Monitor() ~ delete _;
List<QueuedFileChange> mQueuedFileChanges = new List<QueuedFileChange>() ~ DeleteContainerAndItems!(_);
public Monitor mFileChangeMonitor = new Monitor() ~ delete _;
public int mChangeId;
public ~this()
{
for (var watcher in mWatchers)
{
delete watcher.key;
watcher.value.DeleteUnchecked(); // Allow even when refCount isn't zero
}
delete mWatchers;
}
void FixFilePath(String filePath)
{
String oldPath = scope String(filePath);
filePath.Clear();
Path.GetFullPath(oldPath, filePath);
IDEUtils.FixFilePath(filePath);
if (!Environment.IsFileSystemCaseSensitive)
filePath.ToUpper();
}
void FileChanged(String filePath, String newPath, WatcherChangeTypes changeType)
{
if (changeType == .Renamed)
{
// ALWAYS interpret 'file rename' notifications as a delete of filePath and a create of newPath
// A manual rename in the IDE will have manually processed the rename before we get here, so
// we expect 'filePath' won't actually match anything and the 'newPath' will already be set up
// in the mWatchedFile
FileChanged(filePath, null, .Deleted);
var dirName = scope String();
Path.GetDirectoryPath(filePath, dirName);
dirName.Append(Path.DirectorySeparatorChar);
FileChanged(dirName, newPath, .FileCreated);
return;
}
if ((changeType == .FileCreated) && (gApp.IsFilteredOut(newPath)))
return;
String fixedFilePath = scope String(filePath);
FixFilePath(fixedFilePath);
bool wantLoadContent = false;
if (newPath == null)
{
using (mMonitor.Enter())
{
DepInfo depInfo;
mWatchedFiles.TryGetValue(fixedFilePath, out depInfo);
if (depInfo != null)
wantLoadContent = depInfo.mContent != null;
}
}
//Debug.WriteLine("FileChanged {0} {1} {2}", filePath, newPath, changeType);
String newContent = scope String();
if (wantLoadContent)
{
//TODO: Make this better
for (int32 i = 0; i < 25; i++)
{
if (gApp.LoadTextFile(fixedFilePath, newContent) case .Ok)
break;
Thread.Sleep(10);
}
}
using (mMonitor.Enter())
{
DepInfo depInfo;
mWatchedFiles.TryGetValue(fixedFilePath, out depInfo);
if (depInfo == null)
return;
if (depInfo.mContent != null)
{
/*File.WriteAllText(@"c:\\temp\\file1.txt", newContent);
File.WriteAllText(@"c:\\temp\\file2.txt", depInfo.mContent);*/
if (newContent == null) // No actual content (file renamed - as part of file.new, file -> file.old, file.new -> file
return;
if ((depInfo.mContent != null) && (Utils.FileTextEquals(depInfo.mContent, newContent)))
return;
// We were only saving this file until the content actually changed
delete depInfo.mContent;
depInfo.mContent = null;
}
bool added = mChangeMap.TryAdd(fixedFilePath, var keyPtr, var valuePtr);
if (added)
{
ChangeRecord changeRecord = new .();
changeRecord.mPath = new String(fixedFilePath);
changeRecord.mChangeType = changeType;
*keyPtr = changeRecord.mPath;
*valuePtr = changeRecord;
mChangeList.Add(changeRecord);
}
else
{
let changeRecord = *valuePtr;
changeRecord.mChangeType |= changeType;
}
ProjectItem projectItem = null;
for (var dep in depInfo.mDependentObjects)
{
if (var tryProjectItem = dep as ProjectItem)
projectItem = tryProjectItem;
if ((dep != null) && (!mDependencyChangeList.Contains(dep)))
{
mDependencyChangeList.Add(dep);
}
}
if (projectItem != null)
gApp.OnWatchedFileChanged(projectItem, changeType, newPath);
}
}
public void OmitFileChange(String filePath, String content = null)
{
String fixedFilePath = scope String(filePath);
FixFilePath(fixedFilePath);
using (mMonitor.Enter())
{
DepInfo depInfo;
mWatchedFiles.TryGetValue(fixedFilePath, out depInfo);
if (depInfo != null)
{
String.NewOrSet!(depInfo.mContent, content);
}
}
}
public void FileChanged(String filePath)
{
FileChanged(filePath, null, WatcherChangeTypes.Changed);
}
void TryAddRefreshWatchEntry(WatcherEntry watcherEntry, int32 delay = 0)
{
Debug.Assert(watcherEntry != null);
Debug.Assert(watcherEntry.mParentDirWatcher == null);
bool found = false;
for (int32 i = 0; i < mQueuedRefreshWatcherEntries.Count; i++)
{
var refreshEntry = ref mQueuedRefreshWatcherEntries[i];
if (refreshEntry.mWatcherEntry == watcherEntry)
{
refreshEntry.mDelay = Math.Min(refreshEntry.mDelay, delay);
found = true;
}
}
if (!found)
{
QueuedRefreshEntry refreshEntry;
watcherEntry.AddRef();
refreshEntry.mWatcherEntry = watcherEntry;
refreshEntry.mDelay = delay;
mQueuedRefreshWatcherEntries.Add(refreshEntry);
}
}
void QueueFileChanged(FileSystemWatcher fileSystemWatcher, String fileName, String newName, WatcherChangeTypes changeType)
{
//Debug.WriteLine("QueueFileChanged {0} {1} {2} {3}", fileSystemWatcher.Directory, fileName, newName, changeType);
using (mFileChangeMonitor.Enter())
{
String fullPath = scope String();
fullPath.Append(fileSystemWatcher.Directory);
if (fileName != null)
{
fullPath.Append(Path.DirectorySeparatorChar);
fullPath.Append(fileName);
}
var queuedFileChange = new QueuedFileChange();
if ((changeType == .FileCreated) || (changeType == .DirectoryCreated))
{
queuedFileChange.mFileName = new String();
Path.GetDirectoryPath(fullPath, queuedFileChange.mFileName);
queuedFileChange.mFileName.Append(Path.DirectorySeparatorChar);
queuedFileChange.mNewFileName = new String(fullPath);
}
else
{
queuedFileChange.mFileName = new String(fullPath);
if (newName != null)
{
var newFullPath = new String();
Path.GetDirectoryPath(fullPath, newFullPath);
newFullPath.Append(Path.DirectorySeparatorChar);
newFullPath.Append(newName);
queuedFileChange.mNewFileName = newFullPath;
}
}
queuedFileChange.mChangeType = changeType;
mQueuedFileChanges.Add(queuedFileChange);
mChangeId++;
}
}
void StartDirectoryWatcher(WatcherEntry watcherEntry)
{
FileSystemWatcher fileSystemWatcher = null;
//Debug.WriteLine("StartDirectoryWatcher {0}", watcherEntry.mDirectoryName);
//Console.WriteLine("StartDirectoryWatcher");
fileSystemWatcher = new FileSystemWatcher(watcherEntry.mDirectoryName);
fileSystemWatcher.IncludeSubdirectories = watcherEntry.mHasSubDirDependencies;
delete watcherEntry.mFileSystemWatcher;
watcherEntry.mFileSystemWatcher = null;
void GetPath(String fileName, String outPath)
{
outPath.Append(watcherEntry.mDirectoryName);
outPath.Append(Path.DirectorySeparatorChar);
outPath.Append(fileName);
}
void CheckFileCreated(String fileName)
{
if (sDbgFileCreateDelay > 0)
Thread.Sleep(sDbgFileCreateDelay);
var filePath = scope String();
GetPath(fileName, filePath);
if (File.Exists(filePath))
{
QueueFileChanged(fileSystemWatcher, fileName, null, .FileCreated);
}
else if (Directory.Exists(filePath))
QueueFileChanged(fileSystemWatcher, fileName, null, .DirectoryCreated);
else
{
using (mFileChangeMonitor.Enter())
{
if (watcherEntry.mAmbiguousCreatePaths.TryAdd(fileName, var entryPtr))
*entryPtr = new String(fileName);
}
}
}
bool HasAmbiguousFileName(String fileName)
{
switch (watcherEntry.mAmbiguousCreatePaths.GetAndRemove(fileName))
{
case .Ok(let str):
delete str;
return true;
case .Err:
return false;
}
}
if (!watcherEntry.mIgnoreWrites)
fileSystemWatcher.OnChanged.Add(new (fileName) =>
{
using (mFileChangeMonitor.Enter())
{
if (HasAmbiguousFileName(fileName))
{
CheckFileCreated(fileName);
}
QueueFileChanged(fileSystemWatcher, fileName, null, .Changed);
}
});
fileSystemWatcher.OnCreated.Add(new (fileName) =>
{
CheckFileCreated(fileName);
});
fileSystemWatcher.OnDeleted.Add(new (fileName) =>
{
using (mFileChangeMonitor.Enter())
{
if (HasAmbiguousFileName(fileName))
{
// We didn't process the CREATE so just ignore the DELETE
}
else
QueueFileChanged(fileSystemWatcher, fileName, null, .Deleted);
}
});
fileSystemWatcher.OnRenamed.Add(new (oldName, newName) =>
{
using (mFileChangeMonitor.Enter())
{
if (HasAmbiguousFileName(oldName))
{
// We didn't process the CREATE so treat this as a new CREATE
CheckFileCreated(newName);
}
else
QueueFileChanged(fileSystemWatcher, oldName, newName, .Renamed);
}
});
fileSystemWatcher.OnError.Add(new () => QueueFileChanged(fileSystemWatcher, null, null, .Failed));
if (fileSystemWatcher.StartRaisingEvents() case .Err)
{
delete fileSystemWatcher;
//TryAddRefreshWatchEntry(watcherEntry, 30); // Try again later?
}
else
{
fileSystemWatcher.OnError.Add(new () =>
{
if (watcherEntry.mFileSystemWatcher == fileSystemWatcher)
{
TryAddRefreshWatchEntry(watcherEntry);
}
});
watcherEntry.mFileSystemWatcher = fileSystemWatcher;
}
}
// This corrects an error where we attempted to watch a directory that wasn't valid but now it is
public void FileIsValid(String filePath)
{
String fixedFilePath = scope String(filePath);
FixFilePath(fixedFilePath);
using (mMonitor.Enter())
{
String directoryName = scope String();
Path.GetDirectoryPath(fixedFilePath, directoryName);
WatcherEntry watcherEntry;
mWatchers.TryGetValue(directoryName, out watcherEntry);
if (watcherEntry != null)
{
if ((watcherEntry.mFileSystemWatcher == null) && (watcherEntry.mParentDirWatcher == null))
{
TryAddRefreshWatchEntry(watcherEntry);
}
}
}
}
public void WatchFile(String filePath, Object dependentObject = null, bool ignoreWrites = false)
{
//Debug.WriteLine("WatchFile {0}", filePath);
#if !CLI
String fixedFilePath = scope String(filePath);
FixFilePath(fixedFilePath);
using (mMonitor.Enter())
{
DepInfo depInfo;
mWatchedFiles.TryGetValue(fixedFilePath, out depInfo);
if (depInfo != null)
{
depInfo.mDependentObjects.Add(dependentObject);
return;
}
depInfo = new DepInfo();
depInfo.mDependentObjects.Add(dependentObject);
mWatchedFiles[new String(fixedFilePath)] = depInfo;
String directoryName = scope String();
Path.GetDirectoryPath(fixedFilePath, directoryName);
mWatchers.TryGetValue(directoryName, var watcherEntry);
if (watcherEntry != null)
{
watcherEntry.AddRef();
}
else
{
directoryName = new String(directoryName);
watcherEntry = new WatcherEntry();
watcherEntry.mDirectoryName = directoryName;
watcherEntry.mIgnoreWrites = ignoreWrites;
String checkDir = scope String()..Append(directoryName);
while (true)
{
String parentDirName = scope String();
if (Path.GetDirectoryPath(checkDir, parentDirName) case .Err)
break;
if (mWatchers.TryGetValue(parentDirName, var parentWatcherEntry))
{
while (parentWatcherEntry.mParentDirWatcher != null)
parentWatcherEntry = parentWatcherEntry.mParentDirWatcher;
parentWatcherEntry.AddRef();
watcherEntry.mParentDirWatcher = parentWatcherEntry;
if (!parentWatcherEntry.mHasSubDirDependencies)
{
// Restart the watcher with the IncludeSubdirectories flag
parentWatcherEntry.mHasSubDirDependencies = true;
StartDirectoryWatcher(parentWatcherEntry);
}
break;
}
checkDir.Set(parentDirName);
}
if (watcherEntry.mParentDirWatcher == null)
StartDirectoryWatcher(watcherEntry);
mWatchers[directoryName] = watcherEntry;
}
}
#endif
}
public void DerefWatcherEntry(WatcherEntry watchEntry)
{
if (watchEntry.ReleaseRefNoDelete() == 0)
{
if (mWatchers.GetAndRemove(watchEntry.mDirectoryName) case .Ok((var key, var value)))
{
if (watchEntry.mParentDirWatcher != null)
DerefWatcherEntry(watchEntry.mParentDirWatcher);
Debug.Assert(watchEntry == value);
delete key;
delete watchEntry;
}
}
}
public void RemoveWatch(String filePath, Object dependentObject = null)
{
#if !CLI
String fixedFilePath = scope String(filePath);
FixFilePath(fixedFilePath);
using (mMonitor.Enter())
{
DepInfo depInfo;
String outKey;
if (!mWatchedFiles.TryGetValue(fixedFilePath, out outKey, out depInfo))
return;
depInfo.mDependentObjects.Remove(dependentObject);
if (depInfo.mDependentObjects.Count == 0)
{
mWatchedFiles.Remove(fixedFilePath);
String directoryName = scope String();
Path.GetDirectoryPath(fixedFilePath, directoryName);
WatcherEntry watcherEntry = null;
String key;
mWatchers.TryGetValue(directoryName, out key, out watcherEntry);
DerefWatcherEntry(watcherEntry);
delete outKey;
delete depInfo;
}
mDependencyChangeList.Remove(dependentObject);
}
#endif
}
public void Update(Action<String, String, WatcherChangeTypes> fileChangeHandler = null)
{
while (true)
{
QueuedFileChange queuedFileChange;
using (mFileChangeMonitor.Enter())
{
if (mQueuedFileChanges.Count == 0)
break;
queuedFileChange = mQueuedFileChanges.PopFront();
}
if (fileChangeHandler != null)
fileChangeHandler(queuedFileChange.mFileName, queuedFileChange.mNewFileName, queuedFileChange.mChangeType);
FileChanged(queuedFileChange.mFileName, queuedFileChange.mNewFileName, queuedFileChange.mChangeType);
delete queuedFileChange;
}
using (mMonitor.Enter())
{
if (mQueuedRefreshWatcherEntries.Count == 0)
return;
ref QueuedRefreshEntry refreshEntry = ref mQueuedRefreshWatcherEntries[0];
Debug.Assert(refreshEntry.mWatcherEntry != null);
if (refreshEntry.mDelay > 0)
{
refreshEntry.mDelay--;
}
else
{
StartDirectoryWatcher(refreshEntry.mWatcherEntry);
DerefWatcherEntry(refreshEntry.mWatcherEntry);
mQueuedRefreshWatcherEntries.RemoveAt(0);
}
}
}
public ChangeRecord PopChangedFile()
{
using (mMonitor.Enter())
{
if (mChangeList.Count == 0)
return null;
let changeRecord = mChangeList[0];
bool removed = mChangeMap.Remove(changeRecord.mPath);
Debug.Assert(removed);
mChangeList.RemoveAt(0);
return changeRecord;
}
}
public void AddChangedFile(ChangeRecord changeRecord)
{
using (mMonitor.Enter())
{
mChangeList.Add(changeRecord);
bool added = mChangeMap.TryAdd(changeRecord.mPath, changeRecord);
Debug.Assert(added);
}
}
public Object PopChangedDependency()
{
using (mMonitor.Enter())
{
if (mDependencyChangeList.Count == 0)
return null;
Object dep = mDependencyChangeList[0];
mDependencyChangeList.RemoveAt(0);
return dep;
}
}
public void AddChangedDependency(Object obj)
{
using (mMonitor.Enter())
{
mDependencyChangeList.Add(obj);
}
}
}
}

155
IDE/src/HistoryManager.bf Normal file
View file

@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using IDE.ui;
using Beefy;
using System.IO;
namespace IDE
{
public class HistoryEntry : TrackedTextElement
{
//public String mNotes ~ delete _;
public bool mNoMerge;
public this()
{
mSnapToLineStart = false;
}
public ~this()
{
}
}
public class HistoryManager
{
const int32 LINE_MERGE_MAX_DELTA = 8;
const int32 MAX_ENTRIES = 24;
public List<HistoryEntry> mHistoryList = new List<HistoryEntry>() ~
{
for (var entry in _)
entry.Deref();
delete _;
};
public int32 mHistoryIdx = -1;
public HistoryEntry CreateHistory(SourceViewPanel sourceViewPanel, String fileName, int wantLineNum, int wantColumn, bool ignoreIfClose)
{
// If we are backwards in history, try to update the current entry if we're close to it.
// Otherwise we truncate the history from the current location and append a new entry
HistoryEntry historyEntry;
if (mHistoryIdx >= 0)
{
historyEntry = mHistoryList[mHistoryIdx];
if ((!historyEntry.mNoMerge) && (historyEntry.mFileName == fileName) && (Math.Abs(historyEntry.mLineNum - wantLineNum) <= LINE_MERGE_MAX_DELTA))
{
if (ignoreIfClose)
return null;
historyEntry.mMoveIdx++;
historyEntry.mLineNum = (int32)wantLineNum;
historyEntry.mColumn = (int32)wantColumn;
bool foundExistingTrackedElement = false;
if ((sourceViewPanel != null) && (sourceViewPanel.mTrackedTextElementViewList != null))
{
for (var trackedElement in sourceViewPanel.mTrackedTextElementViewList)
{
if (trackedElement.mTrackedElement == historyEntry)
{
sourceViewPanel.UpdateTrackedElementView(trackedElement);
foundExistingTrackedElement = true;
break;
}
}
}
if (!foundExistingTrackedElement)
IDEApp.sApp.mDebugger.mBreakpointsChangedDelegate();
return historyEntry;
}
}
int32 removeIdx = mHistoryIdx + 1;
while (removeIdx < mHistoryList.Count)
DeleteHistory(mHistoryList[removeIdx]);
while (mHistoryList.Count > MAX_ENTRIES)
{
var entry = mHistoryList.PopFront();
entry.Kill();
}
mHistoryIdx = (int32)mHistoryList.Count;
historyEntry = new HistoryEntry();
historyEntry.mFileName = new String(fileName);
historyEntry.mLineNum = (int32)wantLineNum;
historyEntry.mColumn = (int32)wantColumn;
mHistoryList.Add(historyEntry);
IDEApp.sApp.mDebugger.mBreakpointsChangedDelegate();
return historyEntry;
}
public void DeleteHistory(HistoryEntry history)
{
mHistoryList.Remove(history);
if (mHistoryIdx >= mHistoryList.Count)
mHistoryIdx = (int32)mHistoryList.Count - 1;
IDEApp.sApp.mDebugger.mBreakpointsChangedDelegate();
history.Kill();
}
public bool IsAtCurrentHistory(SourceViewPanel sourceViewPanel, String fileName, int wantLineNum, int wantColumn, bool ignoreIfClose)
{
if (mHistoryIdx >= 0)
{
HistoryEntry historyEntry = mHistoryList[mHistoryIdx];
if ((Path.Equals(historyEntry.mFileName, fileName)) && (Math.Abs(historyEntry.mLineNum - wantLineNum) == 0))
{
return true;
}
}
return false;
}
public void GoToCurrentHistory()
{
if (mHistoryIdx == -1)
return;
var History = mHistoryList[mHistoryIdx];
IDEApp.sApp.ShowSourceFileLocation(History.mFileName, -1, -1, History.mLineNum, History.mColumn, LocatorType.Smart);
}
public void PrevHistory()
{
if (mHistoryList.Count == 0)
return;
mHistoryIdx--;
if (mHistoryIdx < 0)
mHistoryIdx = 0;
GoToCurrentHistory();
}
public void NextHistory()
{
if (mHistoryList.Count == 0)
return;
mHistoryIdx++;
if (mHistoryIdx >= mHistoryList.Count)
mHistoryIdx = (int32)mHistoryList.Count - 1;
GoToCurrentHistory();
}
}
}

12473
IDE/src/IDEApp.bf Normal file

File diff suppressed because it is too large Load diff

304
IDE/src/IDEUtils.bf Normal file
View file

@ -0,0 +1,304 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Beefy.widgets;
using Beefy.utils;
using System.Runtime.InteropServices;
using Beefy;
using Beefy.gfx;
using Beefy.theme.dark;
namespace IDE
{
public static class IDEUtils
{
public const char8 cNativeSlash = Path.DirectorySeparatorChar;
public const char8 cOtherSlash = Path.AltDirectorySeparatorChar;
public static void AppendWithOptionalQuotes(String targetStr, String srcFileName)
{
if (!srcFileName.Contains(' '))
targetStr.Append(srcFileName);
else
targetStr.Append("\"", srcFileName, "\"");
}
public static bool FixFilePath(String filePath, char8 wantSlash, char8 otherSlash)
{
if (filePath.Length == 0)
return false;
if (filePath[0] == '<')
return false;
if ((filePath.Length > 1) && (filePath[1] == ':'))
filePath[0] = filePath[0].ToLower;
bool prevWasSlash = false;
for (int i = 0; i < filePath.Length; i++)
{
if (filePath[i] == otherSlash)
filePath[i] = wantSlash;
if (filePath[i] == wantSlash)
{
if ((prevWasSlash) && (i > 1))
{
filePath.Remove(i);
i--;
continue;
}
prevWasSlash = true;
}
else
prevWasSlash = false;
if ((i >= 4) && (filePath[i - 3] == wantSlash) && (filePath[i - 2] == '.') && (filePath[i - 1] == '.') && (filePath[i] == wantSlash))
{
int prevSlash = filePath.LastIndexOf(wantSlash, i - 4);
if (prevSlash != -1)
{
if ((i - prevSlash != 6) || (filePath[prevSlash + 1] != '.') || (filePath[prevSlash + 2] != '.'))
{
filePath.Remove(prevSlash, i - prevSlash);
i = prevSlash;
}
}
}
}
return true;
}
public static bool FixFilePath(String filePath)
{
return FixFilePath(filePath, cNativeSlash, cOtherSlash);
}
public static bool MakeComparableFilePath(String filePath)
{
bool success = FixFilePath(filePath, cNativeSlash, cOtherSlash);
if (!Environment.IsFileSystemCaseSensitive)
filePath.ToUpper();
return success;
}
public static bool CanonicalizeFilePath(String filePath)
{
return FixFilePath(filePath, '/', '\\');
}
public static void AddSortedEntries(List<String> stringList, IEnumerator<String> strs)
{
for (var str in strs)
stringList.Add(str);
//TODO: Sort
}
public static bool IsHeaderFile(String fileName)
{
return fileName.EndsWith(".h", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".hpp", StringComparison.OrdinalIgnoreCase);
}
public static int64 GetLastModifiedTime(String filePath)
{
DateTime dt = File.GetLastWriteTime(filePath);
//return dt.ToFileTime();
//ThrowUnimplemented();
return dt.ToFileTime();
}
public static void SelectNextChildWidget(Widget parentWidget, bool doBackwards)
{
Widget firstTabWidget = null;
Widget lastTabWidget = null;
bool prevWasSelected = false;
for (var childWidget in parentWidget.mChildWidgets)
{
if ((!doBackwards) && (prevWasSelected))
{
childWidget.SetFocus();
return;
}
if ((childWidget.mHasFocus) && (lastTabWidget != null))
{
lastTabWidget.SetFocus();
return;
}
prevWasSelected = childWidget.mHasFocus;
if (firstTabWidget == null)
firstTabWidget = childWidget;
lastTabWidget = childWidget;
}
if ((!doBackwards) && (firstTabWidget != null))
firstTabWidget.SetFocus();
if ((doBackwards) && (lastTabWidget != null))
lastTabWidget.SetFocus();
}
public static void SerializeListViewState(StructuredData data, ListView listView)
{
using (data.CreateArray("Columns", true))
{
for (var column in listView.mColumns)
{
using (data.CreateObject())
{
data.Add("Width", column.mWidth);
}
}
}
}
public static void DeserializeListViewState(StructuredData data, ListView listView)
{
//using (data.Open("Columns"))
int columnIdx = 0;
for (var _t in data.Enumerate("Columns"))
{
//for (int32 columnIdx = 0; columnIdx < data.Count; columnIdx++)
{
//using (data.Open(@columnKV))
{
listView.mColumns[columnIdx].mWidth = data.GetFloat("Width");
}
++columnIdx;
}
}
}
public static void DrawWait(Graphics g, float x, float y, int updateCnt)
{
var image = DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.WaitSegment);
image.mPixelSnapping = PixelSnapping.Never;
float colorPct = updateCnt / 100.0f;
colorPct -= (int32)colorPct;
for (int32 i = 0; i < 8; i++)
{
float brightness = 1.0f;
float wheelPct = i / 8.0f;
float dist;
if (wheelPct > colorPct)
dist = (1.0f - wheelPct) + colorPct;
else
dist = colorPct - wheelPct;
brightness -= dist * 1.0f;
Matrix mat = Matrix.IdentityMatrix;
mat.Translate(-9.5f, -14);
mat.Rotate(Math.PI_f * i / 4);
mat.Translate(x, y);
using (g.PushColor(Color.Get(brightness)))
using (g.PushMatrix(mat))
g.Draw(image);
}
}
public static void DrawOutline(Graphics g, Widget widget, int inflateX, int inflateY, uint32 color)
{
using (g.PushColor(color))
{
g.OutlineRect(widget.mX - inflateX, widget.mY - inflateY, widget.mWidth + inflateX * 2, widget.mHeight + inflateY * 2);
}
}
public static void DrawOutline(Graphics g, Widget widget, int inflateX = 0, int32 inflateY = 0)
{
DrawOutline(g, widget, inflateX, inflateY, IDEApp.cDialogOutlineLightColor);
DrawOutline(g, widget, inflateX - 1, inflateY - 1, IDEApp.cDialogOutlineDarkColor);
}
public static void ClampMenuCoords(ref float x, ref float y, ScrollableWidget scrollableWidget, Insets insets = null)
{
var insets;
if (insets == null)
insets = scope:: .();
var visibleContentRange = scrollableWidget.GetVisibleContentRange();
if (y > visibleContentRange.Bottom)
y = visibleContentRange.Bottom - insets.mBottom;
if (y < visibleContentRange.Top)
y = visibleContentRange.Top + insets.mTop;
if (x > visibleContentRange.Right)
x = visibleContentRange.Right - insets.mRight;
if (x < visibleContentRange.Left)
x = visibleContentRange.Left + insets.mLeft;
}
public static void DrawLock(Graphics g, float x, float y, bool isLocked, float pct)
{
if (pct > 0)
{
int32 circleCount = 2;
for (int32 i = 0; i < circleCount; i++)
{
float sepPct = 0.3f;
float maxSep = (circleCount - 2) * sepPct;
float circlePct = (pct - maxSep + (i * 0.3f)) / (1.0f - maxSep);
if ((circlePct < 0.0f) || (circlePct > 1.0f))
continue;
float scale = (float)Math.Sin(circlePct * Math.PI_f / 2) * 0.8f;
float alpha = Math.Min(1.0f, (1.0f - (float)Math.Sin(circlePct * Math.PI_f / 2)) * 1.0f);
using (g.PushTranslate(x - GS!(22), y - GS!(22)))
{
using (g.PushColor(Color.Get(0x00FF0000, alpha)))
{
using (g.PushScale(scale, scale, GS!(32), GS!(32)))
g.Draw(IDEApp.sApp.mCircleImage);
}
}
}
}
using (g.PushColor(isLocked ? 0xFFFFFFFF : 0x80000000))
{
var x;
var y;
if (pct > 0)
{
let rand = scope Random((int32)(Math.Pow(pct, 0.6f) * 20));
x += (float)rand.NextDoubleSigned() * (1.5f - pct);
y += (float)rand.NextDoubleSigned() * (1.5f - pct);
}
g.Draw(DarkTheme.sDarkTheme.GetImage(.LockIcon), x, y);
}
}
}
}
static
{
public static mixin Set(String val1, String val2)
{
val1.Set(val2);
}
public static mixin Set(List<String> val1, List<String> val2)
{
ClearAndDeleteItems(val1);
for (var str in val2)
val1.Add(new String(str));
}
public static mixin Set(var val1, var val2)
{
val1 = val2;
}
}

131
IDE/src/IPCHelper.bf Normal file
View file

@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
namespace IDE
{
public class IPCHelper
{
#if BF_PLATFORM_WINDOWS
public const int32 cBufferSize = 1024;
public Windows.Handle mPipeHandle ~ _.Close();
public bool mHasConnection;
public String mBuffer = new String() ~ delete _;
public List<String> mMessages = new List<String>() ~ DeleteContainerAndItems!(_);
public ~this()
{
}
public bool Init(String name)
{
String pipeName = scope String(@"\\.\pipe\", name);
mPipeHandle = Windows.CreateNamedPipeA(pipeName, Windows.PIPE_ACCESS_DUPLEX, // read/write access
Windows.PIPE_TYPE_MESSAGE | // message type pipe
Windows.PIPE_READMODE_MESSAGE | // message-read mode
Windows.PIPE_NOWAIT,
1/*Windows.PIPE_UNLIMITED_INSTANCES*/, // max. instances
cBufferSize, // output buffer size
cBufferSize, // input buffer size
0 /*NMPWAIT_USE_DEFAULT_WAIT*/, // client time-out
null);
if (mPipeHandle.IsInvalid)
{
// Someone else has the IPC pipe open, ask them to shut it down (asserting that WE are the app that wants to host it now)
#unwarn
int32 lastError = Windows.GetLastError();
Windows.FileHandle fileHandle = Windows.CreateFileA(pipeName, Windows.FILE_WRITE_DATA, default, null, System.IO.FileMode.Open, 0, 0);
if (fileHandle.IsInvalid)
return false;
String closeCmd = "StopIPC\n";
int32 bytesWritten;
Windows.WriteFile(fileHandle, (uint8*)closeCmd.CStr(), (int32)closeCmd.Length, out bytesWritten, null);
fileHandle.Close();
return false;
}
return true;
}
public void CloseConnection()
{
if (mHasConnection)
{
mHasConnection = false;
Windows.DisconnectNamedPipe(mPipeHandle);
mBuffer.Clear();
}
}
public void Update()
{
if (!mHasConnection)
{
if (!Windows.ConnectNamedPipe(mPipeHandle, null))
{
int32 lastError = Windows.GetLastError();
/*if (lastError == Windows.ERROR_NO_DATA)
{
Windows.DisconnectNamedPipe();
}*/
if (lastError != 536)
{
NOP!();
}
if ((lastError != Windows.ERROR_PIPE_CONNECTED) && (lastError != Windows.ERROR_NO_DATA))
return;
}
mHasConnection = true;
}
uint8* buffer = scope uint8[1024]*;
int32 bytesRead;
int32 result = Windows.ReadFile(mPipeHandle, buffer, 1024, out bytesRead, null);
if ((result <= 0) || (bytesRead == 0))
{
int32 lastError = Windows.GetLastError();
if (lastError == Windows.ERROR_BROKEN_PIPE)
{
CloseConnection();
}
}
else
{
for (int32 i = 0; i < bytesRead; i++)
{
mBuffer.Append((char8)buffer[i]);
}
}
int crPos = mBuffer.IndexOf('\n');
if (crPos > 0)
{
String msg = new String(mBuffer, 0, crPos);
mBuffer.Remove(0, crPos + 1);
mMessages.Add(msg);
}
}
public void Send(String str)
{
int32 bytesWritten;
Windows.WriteFile(mPipeHandle, (uint8*)str.CStr(), (int32)str.Length, out bytesWritten, null);
}
public String PopMessage()
{
if (mMessages.Count == 0)
return null;
return mMessages.PopFront();
}
#endif //BF_PLATFORM_WINDOWS
}
}

23
IDE/src/Popup.bf Normal file
View file

@ -0,0 +1,23 @@
#if false
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Beefy.widgets;
using Beefy.gfx;
namespace IDE
{
public class Popup : Widget
{
public override void Draw(Graphics g)
{
base.Draw(g);
using (g.PushColor(0xFFFF8080))
g.FillRect(0, 0, mWidth - 20, mHeight - 20);
}
}
}
#endif

155
IDE/src/Program.bf Normal file
View file

@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
using IDE.Debugger;
using System.IO;
using Beefy;
using Beefy.utils;
using IDE.Util;
namespace IDE
{
public class Program
{
//System.Collections.Generic.List<System.String> list;
static int32 Main(String[] args)
{
/*if ((var str = scope String()) || (var str2 = scope String()))
{
}*/
//Test.Test();
#if SMALLTEST
Debug.WriteLine("Hey!\n");
#else
IDEApp mApp = new IDEApp();
mApp.ParseCommandLine(args);
mApp.Init();
/*mApp.mScriptManager.mExpectingError = new String("Fart");
mApp.mRunningTestScript = true;
mApp.Fail("Fart");*/
mApp.Run();
mApp.Shutdown();
int32 retVal = mApp.mFailed ? 1 : 0;
delete mApp;
//TODO: REMOVE!
//Thread.Sleep(30000);
#endif
return retVal;
}
}
}
namespace A0
{
[AlwaysInclude]
static class ProgramDtor
{
static ~this()
{
IDE.Debugger.DebugManager.ProgramDone();
#if BF_PLATFORM_WINDOWS
if (IDE.IDEApp.sExitTest)
{
Internal.ReportMemory();
GC.Report();
GC.DebugDumpLeaks();
GC.Shutdown();
Windows.MessageBoxA((Windows.HWnd)0, "Hey", "Yo", 0);
}
#endif
}
static void Test()
{
/*int a;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;
a = 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1;*/
}
}
}

2180
IDE/src/Project.bf Normal file

File diff suppressed because it is too large Load diff

1759
IDE/src/ScriptManager.bf Normal file

File diff suppressed because it is too large Load diff

776
IDE/src/Settings.bf Normal file
View file

@ -0,0 +1,776 @@
using System.Collections.Generic;
using System;
using Beefy.gfx;
using Beefy.geom;
using Beefy.widgets;
using System.Threading;
using Beefy.utils;
using IDE.util;
namespace IDE
{
[Reflect(.All | .ApplyToInnerTypes)]
class Settings
{
public class VSSettings
{
public String mBin32Path = new .() ~ delete _;
public String mBin64Path = new .() ~ delete _;
public List<String> mLib32Paths = new .() ~ DeleteContainerAndItems!(_);
public List<String> mLib64Paths = new .() ~ DeleteContainerAndItems!(_);
public void Serialize(StructuredData sd)
{
sd.Add("Bin32Path", mBin32Path);
sd.Add("Bin64Path", mBin64Path);
using (sd.CreateArray("Lib32Paths"))
{
for (let str in mLib32Paths)
sd.Add(str);
}
using (sd.CreateArray("Lib64Paths"))
{
for (let str in mLib64Paths)
sd.Add(str);
}
}
public void Deserialize(StructuredData sd)
{
sd.GetString("Bin32Path", mBin32Path);
sd.GetString("Bin64Path", mBin64Path);
ClearAndDeleteItems(mLib32Paths);
for (sd.Enumerate("Lib32Paths"))
{
var str = new String();
sd.GetCurString(str);
mLib32Paths.Add(str);
}
ClearAndDeleteItems(mLib64Paths);
for (sd.Enumerate("Lib64Paths"))
{
var str = new String();
sd.GetCurString(str);
mLib64Paths.Add(str);
}
}
[CLink, StdCall]
static extern char8* VSSupport_Find();
public bool IsConfigured()
{
return !mLib32Paths.IsEmpty || !mLib64Paths.IsEmpty || !mBin32Path.IsEmpty || !mBin64Path.IsEmpty;
}
public void SetDefaults()
{
#if BF_PLATFORM_WINDOWS
StringView vsInfo = .(VSSupport_Find());
for (var infoStr in vsInfo.Split('\n'))
{
if (infoStr.IsEmpty)
continue;
var infos = infoStr.Split('\t');
switch (infos.GetNext().Get())
{
case "TOOL32":
mBin32Path.Set(infos.GetNext());
case "TOOL64":
mBin64Path.Set(infos.GetNext());
case "LIB32":
mLib32Paths.Add(new String(infos.GetNext()));
case "LIB64":
mLib64Paths.Add(new String(infos.GetNext()));
}
}
#endif
}
}
public class DebuggerSettings
{
public enum SymbolServerKind
{
Yes,
No,
Ask
}
public SymbolServerKind mUseSymbolServers = .Yes;
public String mSymCachePath = new .("C:\\SymCache") ~ delete _;
public List<String> mSymbolSearchPath = new .() ~ DeleteContainerAndItems!(_);
public List<String> mAutoFindPaths = new .() ~ DeleteContainerAndItems!(_);
public int32 mProfileSampleRate = 1000;
public void Serialize(StructuredData sd)
{
sd.Add("UseSymbolServers", mUseSymbolServers);
sd.Add("SymCachePath", mSymCachePath);
using (sd.CreateArray("SymbolSearchPath"))
{
for (let str in mSymbolSearchPath)
sd.Add(str);
}
using (sd.CreateArray("AutoFindPaths"))
{
for (let str in mAutoFindPaths)
sd.Add(str);
}
using (sd.CreateArray("StepFilters"))
{
for (var stepFilter in gApp.mDebugger.mStepFilterList.Values)
{
if (!stepFilter.mIsGlobal)
continue;
if (stepFilter.mKind == .Filtered)
sd.Add(stepFilter.mFilter);
}
sd.RemoveIfEmpty();
}
using (sd.CreateArray("StepNotFilters"))
{
for (var stepFilter in gApp.mDebugger.mStepFilterList.Values)
{
if (!stepFilter.mIsGlobal)
continue;
if (stepFilter.mKind == .NotFiltered)
sd.Add(stepFilter.mFilter);
}
sd.RemoveIfEmpty();
}
sd.Add("ProfileSampleRate", mProfileSampleRate);
}
public void Deserialize(StructuredData sd)
{
sd.Get("UseSymbolServers", ref mUseSymbolServers);
sd.Get("SymCachePath", mSymCachePath);
ClearAndDeleteItems(mSymbolSearchPath);
for (sd.Enumerate("SymbolSearchPath"))
{
var str = new String();
sd.GetCurString(str);
mSymbolSearchPath.Add(str);
}
ClearAndDeleteItems(mAutoFindPaths);
for (sd.Enumerate("AutoFindPaths"))
{
var str = new String();
sd.GetCurString(str);
mAutoFindPaths.Add(str);
}
if (gApp.mDebugger != null)
{
for (sd.Enumerate("StepFilters"))
{
String filter = scope String();
sd.GetCurString(filter);
gApp.mDebugger.CreateStepFilter(filter, true, .Filtered);
}
for (sd.Enumerate("StepNotFilters"))
{
String filter = scope String();
sd.GetCurString(filter);
gApp.mDebugger.CreateStepFilter(filter, true, .NotFiltered);
}
}
sd.Get("ProfileSampleRate", ref mProfileSampleRate);
}
public void Apply()
{
String symbolServerPath = scope String()..Join("\n", mSymbolSearchPath.GetEnumerator());
if (mUseSymbolServers == .No)
{
gApp.mDebugger.SetSymSrvOptions("", "", .Disable);
}
gApp.mDebugger.SetSymSrvOptions(mSymCachePath, symbolServerPath, .None);
mProfileSampleRate = Math.Clamp(mProfileSampleRate, 10, 10000);
}
public void SetDefaults()
{
/*String appDataPath = scope String();
Platform.GetStrHelper(appDataPath, scope (outPtr, outSize, outResult) =>
{
Platform.BfpDirectory_GetSysDirectory(.AppData_Local, outPtr, outSize, (Platform.BfpFileResult*)outResult);
});*/
mSymbolSearchPath.Add(new String("https://msdl.microsoft.com/download/symbols"));
mAutoFindPaths.Add(new String(@"C:\Program Files (x86)\Microsoft Visual Studio*"));
mAutoFindPaths.Add(new String(@"C:\Program Files (x86)\Windows Kits\10\Source"));
}
}
public class CompilerSettings
{
public int32 mWorkerThreads = 6;
public void Serialize(StructuredData sd)
{
sd.Add("WorkerThreads", mWorkerThreads);
}
public void Deserialize(StructuredData sd)
{
sd.Get("WorkerThreads", ref mWorkerThreads);
}
public void SetDefaults()
{
Platform.BfpSystemResult result;
mWorkerThreads = Platform.BfpSystem_GetNumLogicalCPUs(&result);
}
}
public class EditorSettings
{
public enum LockWhileDebuggingKind
{
Never,
Always,
WhenNotHotSwappable
}
public enum AutoCompleteShowKind
{
Popup,
Panel,
PanelIfVisible,
None
}
public class Colors
{
public Color mUIColorR = Color.Get(255, 0, 0);
public Color mUIColorG = Color.Get(0, 255, 0);
public Color mUIColorB = Color.Get(0, 0, 255);
public Color mText = 0xFFFFFFFF;
public Color mKeyword = 0xFFE1AE9A;
public Color mLiteral = 0XFFC8A0FF;
public Color mIdentifier = 0xFFFFFFFF;
public Color mType = 0XFF66D9EF;
public Color mComment = 0XFF75715E;
public Color mMethod = 0XFFA6E22A;
public Color mTypeRef = 0XFF66D9EF;
public Color mNamespace = 0xFF7BEEB7;
public Color mDisassemblyText = 0xFFB0B0B0;
public Color mDisassemblyFileName = 0XFFFF0000;
public Color mError = 0xFFFF0000;
public Color mBuildError = 0xFFFF8080;
public Color mBuildWarning = 0xFFFFFF80;
public Color mVisibleWhiteSpace = 0xFF9090C0;
public void Serialize(StructuredData sd)
{
}
public void Deserialize(StructuredData sd)
{
}
}
public List<String> mFonts = new .() ~ DeleteContainerAndItems!(_);
public float mFontSize = 12;
public float mUIScale = 100;
public Colors mColors = new .() ~ delete _;
public AutoCompleteShowKind mAutoCompleteShowKind = .PanelIfVisible;
public bool mAutoCompleteRequireTab = false;
public bool mAutoCompleteShowDocumentation = true;
public bool mShowLocatorAnim = true;
public bool mHiliteCursorReferences = true;
public bool mLockEditing;
public LockWhileDebuggingKind mLockEditingWhenDebugging = .WhenNotHotSwappable; // Only applicable for non-Beef sources
public bool mPerforceAutoCheckout = true;
public bool mSpellCheckEnabled = true;
public bool mShowLineNumbers = true;
public void Serialize(StructuredData sd)
{
using (sd.CreateArray("Fonts"))
{
for (let str in mFonts)
sd.Add(str);
}
sd.Add("FontSize", mFontSize);
sd.Add("UIScale", mUIScale);
sd.Add("AutoCompleteShowKind", mAutoCompleteShowKind);
sd.Add("AutoCompleteRequireTab", mAutoCompleteRequireTab);
sd.Add("AutoCompleteShowDocumentation", mAutoCompleteShowDocumentation);
sd.Add("ShowLocatorAnim", mShowLocatorAnim);
sd.Add("HiliteCursorReferences", mHiliteCursorReferences);
sd.Add("LockEditing", mLockEditing);
sd.Add("LockEditingWhenDebugging", mLockEditingWhenDebugging);
sd.Add("PerforceAutoCheckout", mPerforceAutoCheckout);
sd.Add("SpellCheckEnabled", mSpellCheckEnabled);
sd.Add("ShowLineNumbers", mShowLineNumbers);
using (sd.CreateObject("Colors"))
mColors.Serialize(sd);
}
public void Deserialize(StructuredData sd)
{
ClearAndDeleteItems(mFonts);
for (sd.Enumerate("Fonts"))
{
var str = new String();
sd.GetCurString(str);
mFonts.Add(str);
}
sd.Get("FontSize", ref mFontSize);
sd.Get("UIScale", ref mUIScale);
sd.Get("AutoCompleteShowKind", ref mAutoCompleteShowKind);
sd.Get("AutoCompleteRequireTab", ref mAutoCompleteRequireTab);
sd.Get("AutoCompleteShowDocumentation", ref mAutoCompleteShowDocumentation);
sd.Get("ShowLocatorAnim", ref mShowLocatorAnim);
sd.Get("HiliteCursorReferences", ref mHiliteCursorReferences);
sd.Get("LockEditing", ref mLockEditing);
sd.Get("LockEditingWhenDebugging", ref mLockEditingWhenDebugging);
sd.Get("PerforceAutoCheckout", ref mPerforceAutoCheckout);
sd.Get("SpellCheckEnabled", ref mSpellCheckEnabled);
sd.Get("ShowLineNumbers", ref mShowLineNumbers);
using (sd.Open("Colors"))
mColors.Deserialize(sd);
}
public void SetDefaults()
{
mFonts.Add(new String("fonts/SourceCodePro-Regular.ttf"));
mFonts.Add(new String("Segoe UI"));
mFonts.Add(new String("Segoe UI Symbol"));
mFonts.Add(new String("Segoe UI Historic"));
mFonts.Add(new String("Segoe UI Emoji"));
}
public void Apply()
{
if (mSpellCheckEnabled)
{
if (gApp.mSpellChecker == null)
gApp.CreateSpellChecker();
}
else
{
if (gApp.mSpellChecker != null)
DeleteAndNullify!(gApp.mSpellChecker);
}
}
}
public class KeySettings
{
public class Entry
{
public KeyState[] mKeys ~ DeleteContainerAndItems!(_);
public String mCommand ~ delete _;
}
public List<Entry> mEntries = new .() ~ DeleteContainerAndItems!(_);
public void Clear()
{
ClearAndDeleteItems(mEntries);
}
void Add(StringView cmd, StringView keys)
{
let entry = new Entry();
entry.mCommand = new String(cmd);
let keyList = scope List<KeyState>();
KeyState.Parse(keys, keyList);
let keyArr = new KeyState[keyList.Count];
keyList.CopyTo(keyArr);
entry.mKeys = keyArr;
mEntries.Add(entry);
}
public void SetDefaults()
{
Add("Autocomplete", "Ctrl+Space");
Add("Bookmark Next", "F2");
Add("Bookmark Prev", "Shift+F2");
Add("Bookmark Toggle", "Ctrl+F2");
Add("Bookmark Clear", "Ctrl+K, Ctrl+L");
Add("Break All", "Ctrl+Alt+Break");
Add("Breakpoint Toggle Thread", "Ctrl+F9");
Add("Breakpoint Toggle", "F9");
Add("Build Solution", "F7");
Add("Cancel Build", "Ctrl+Break");
Add("Close Window", "Ctrl+W");
Add("Compile File", "Ctrl+F7");
Add("Find Class", "Alt+Shift+L");
Add("Find in Document", "Ctrl+F");
Add("Find in Files", "Ctrl+Shift+F");
Add("Find Next", "F3");
Add("Find Prev", "Shift+F3");
Add("Goto Definition", "F12");
Add("Goto Line", "Ctrl+G");
Add("Goto Method", "Alt+M");
Add("Goto Next Item", "F4");
Add("Make Lowercase", "Ctrl+U");
Add("Make Uppercase", "Ctrl+Shift+U");
Add("Match Brace Select", "Ctrl+Shift+RBracket");
Add("Match Brace", "Ctrl+RBracket");
Add("Navigate Backwards", "Alt+Left");
Add("Navigate Forwards", "Alt+Right");
Add("Next Document Panel", "Ctrl+Comma");
Add("Open Corresponding", "Alt+O");
Add("Open File in Workspace", "Shift+Alt+O");
Add("Open File", "Ctrl+O");
Add("Open Workspace", "Ctrl+Shift+O");
Add("Remove All Breakpoints", "Ctrl+Shift+F9");
Add("Rename Symbol", "Ctrl+R");
Add("Rename Item", "F2");
Add("Replace in Document", "Ctrl+H");
Add("Replace in Files", "Ctrl+Shift+H");
Add("Report Memory", "Ctrl+Alt+Shift+M");
Add("Run To Cursor", "Ctrl+F10");
Add("Run Without Compiling", "Ctrl+Shift+F5");
Add("Save All", "Ctrl+Shift+S");
Add("Save File", "Ctrl+S");
Add("Set Next Statement", "Ctrl+Shift+F10");
Add("Show Current", "Alt+C");
Add("Show Auto Watches", "Ctrl+Alt+A");
Add("Show Autocomplete Panel", "Ctrl+Alt+U");
Add("Show Breakpoints", "Ctrl+Alt+B");
Add("Show Call Stack", "Ctrl+Alt+C");
Add("Show Class View", "Ctrl+Alt+L");
Add("Show File Externally", "Ctrl+Tilde");
Add("Show Find Results", "Ctrl+Alt+F");
Add("Show Fixit", "Ctrl+Period");
Add("Show Immediate", "Ctrl+Alt+I");
Add("Show Memory", "Ctrl+Alt+M");
Add("Show Modules", "Ctrl+Alt+D");
Add("Show Output", "Ctrl+Alt+O");
Add("Show Profiler", "Ctrl+Alt+P");
Add("Show QuickWatch", "Shift+Alt+W");
Add("Show Threads", "Ctrl+Alt+T");
Add("Show Watches", "Ctrl+Alt+W");
Add("Show Workspace Explorer", "Ctrl+Alt+S");
Add("Start Debugging", "F5");
Add("Start Without Debugging", "Ctrl+F5");
Add("Step Into", "F11");
Add("Step Out", "Shift+F11");
Add("Step Over", "F10");
Add("Stop Debugging", "Shift+F5");
Add("Tab First", "Ctrl+Alt+Home");
Add("Tab Last", "Ctrl+Alt+End");
Add("Tab Next", "Ctrl+Alt+PageDown");
Add("Tab Prev", "Ctrl+Alt+PageUp");
Add("Zoom In", "Ctrl+Equals");
Add("Zoom Out", "Ctrl+Minus");
Add("Zoom Reset", "Ctrl+0");
}
public void Apply()
{
gApp.mCommands.mKeyMap.Clear();
for (let entry in mEntries)
{
var curCmdMap = gApp.mCommands.mKeyMap;
for (let keyState in entry.mKeys)
{
bool isChordEntry = @keyState < entry.mKeys.Count - 1;
IDECommand ideCommand = null;
if (!isChordEntry)
{
if (!gApp.mCommands.mCommandMap.TryGetValue(entry.mCommand, out ideCommand))
{
gApp.OutputLineSmart("ERROR: Unable to locate IDE command {0}", entry.mCommand);
break; // Boo
}
ideCommand.mParent = curCmdMap;
ideCommand.mBoundKeyState = keyState;
}
KeyState* keyStatePtr;
IDECommandBase* valuePtr;
if (curCmdMap.mMap.TryAdd(keyState, out keyStatePtr, out valuePtr))
{
if (isChordEntry)
{
let newCmdMap = new CommandMap();
newCmdMap.mParent = curCmdMap;
newCmdMap.mBoundKeyState = keyState;
curCmdMap = newCmdMap;
*valuePtr = curCmdMap;
}
else
{
*valuePtr = ideCommand;
}
}
else
{
if (isChordEntry)
{
curCmdMap = (*valuePtr) as CommandMap;
if (curCmdMap == null)
break;
}
else
{
var prevIDECommand = (*valuePtr) as IDECommand;
if (prevIDECommand != null)
{
var checkPrevCmd = prevIDECommand;
while (true)
{
if (checkPrevCmd.mContextFlags == ideCommand.mContextFlags)
gApp.OutputLineSmart("ERROR: The same key is bound for '{0}' and '{1}'", checkPrevCmd.mName, entry.mCommand);
if (checkPrevCmd.mNext == null)
break;
checkPrevCmd = checkPrevCmd.mNext;
}
checkPrevCmd.mNext = ideCommand;
}
else
gApp.OutputLineSmart("ERROR: The same key is bound for '{0}' and as part of a key chord", entry.mCommand);
}
}
}
}
String keyStr = scope String();
for (var ideCommand in gApp.mCommands.mCommandMap.Values)
{
if (ideCommand.mMenuItem == null)
continue;
if (ideCommand.mBoundKeyState != null)
{
keyStr.Clear();
keyStr.Append("#");
ideCommand.mBoundKeyState.ToString(keyStr);
ideCommand.mMenuItem.SetHotKey(keyStr);
}
else
ideCommand.mMenuItem.SetHotKey(.());
}
}
public void Serialize(StructuredData sd)
{
let mKeyEntries = scope List<IDECommand>();
for (var kv in gApp.mCommands.mCommandMap)
{
mKeyEntries.Add(kv.value);
}
mKeyEntries.Sort(scope (lhs, rhs) => String.Compare(lhs.mName, rhs.mName, true));
for (var ideCommand in mKeyEntries)
{
String keyStr = scope .();
ideCommand.ToString(keyStr);
sd.Add(ideCommand.mName, keyStr);
}
}
public void Deserialize(StructuredData sd)
{
HashSet<String> usedCommands = scope .();
List<String> allocatedStrs = scope .();
defer { DeleteAndClearItems!(allocatedStrs); }
List<Entry> newEntries = new .();
for (let cmdStr in sd.Enumerate())
{
var keyStr = sd.GetCurrent() as String;
if (keyStr == null)
continue;
if (keyStr.IsWhiteSpace)
{
var str = new String(cmdStr);
usedCommands.Add(str);
allocatedStrs.Add(str);
continue;
}
let entry = new Entry();
entry.mCommand = new String(cmdStr);
let keyList = scope List<KeyState>();
KeyState.Parse(keyStr, keyList);
let keyArr = new KeyState[keyList.Count];
keyList.CopyTo(keyArr);
entry.mKeys = keyArr;
newEntries.Add(entry);
usedCommands.Add(entry.mCommand);
}
for (var entry in mEntries)
{
if (usedCommands.Contains(entry.mCommand))
continue;
newEntries.Add(entry);
mEntries[@entry.Index] = null;
}
DeleteContainerAndItems!(mEntries);
mEntries = newEntries;
}
}
public CompilerSettings mCompilerSettings = new .() ~ delete _;
public EditorSettings mEditorSettings = new .() ~ delete _;
public VSSettings mVSSettings = new .() ~ delete _;
public DebuggerSettings mDebuggerSettings = new .() ~ delete _;
public KeySettings mKeySettings = new .() ~ delete _;
public RecentFiles mRecentFiles = new RecentFiles() ~ delete _;
public String mWakaTimeKey = new .() ~ delete _;
public this()
{
SetDefaults();
}
public void SetDefaults()
{
mVSSettings.SetDefaults();
mEditorSettings.SetDefaults();
mCompilerSettings.SetDefaults();
mDebuggerSettings.SetDefaults();
mKeySettings.SetDefaults();
}
void GetSettingsPath(String outPath)
{
outPath.Append(gApp.mInstallDir, "/BeefSettings.toml");
}
public void Save()
{
String path = scope .();
GetSettingsPath(path);
let sd = scope StructuredData();
sd.CreateNew();
sd.Add("FileVersion", 1);
using (sd.CreateObject("Editor"))
mEditorSettings.Serialize(sd);
using (sd.CreateObject("Keys"))
mKeySettings.Serialize(sd);
using (sd.CreateObject("Compiler"))
mCompilerSettings.Serialize(sd);
using (sd.CreateObject("Debugger"))
mDebuggerSettings.Serialize(sd);
using (sd.CreateObject("VisualStudio"))
mVSSettings.Serialize(sd);
using (sd.CreateObject("RecentFiles"))
{
for (RecentFiles.RecentKind recentKind = default; recentKind < RecentFiles.RecentKind.COUNT; recentKind++)
{
String name = scope .();
recentKind.ToString(name);
using (sd.CreateArray(name))
{
for (var recentFile in mRecentFiles.GetRecentList(recentKind))
sd.Add(recentFile);
}
}
}
sd.Add("WakaTimeKey", mWakaTimeKey);
String dataStr = scope String();
sd.ToTOML(dataStr);
gApp.SafeWriteTextFile(path, dataStr);
}
public void Load()
{
String path = scope .();
GetSettingsPath(path);
let sd = scope StructuredData();
if (sd.Load(path) case .Err)
return;
using (sd.Open("Editor"))
mEditorSettings.Deserialize(sd);
using (sd.Open("Keys"))
mKeySettings.Deserialize(sd);
using (sd.Open("Compiler"))
mCompilerSettings.Deserialize(sd);
using (sd.Open("Debugger"))
mDebuggerSettings.Deserialize(sd);
using (sd.Open("VisualStudio"))
mVSSettings.Deserialize(sd);
using (sd.Open("RecentFiles"))
{
for (RecentFiles.RecentKind recentKind = default; recentKind < RecentFiles.RecentKind.COUNT; recentKind++)
{
let recentList = mRecentFiles.GetRecentList(recentKind);
String name = scope .();
recentKind.ToString(name);
for (sd.Enumerate(name))
{
String fileStr = new String();
sd.GetCurString(fileStr);
IDEUtils.FixFilePath(fileStr);
recentList.Add(fileStr);
}
}
}
sd.Get("WakaTimeKey", mWakaTimeKey);
}
public void Apply()
{
gApp.mSettings.mEditorSettings.mUIScale = Math.Clamp(gApp.mSettings.mEditorSettings.mUIScale, 25, 400);
gApp.mSettings.mEditorSettings.mFontSize = Math.Clamp(gApp.mSettings.mEditorSettings.mFontSize, 6.0f, 72.0f);
Font.ClearFontNameCache();
gApp.SetScale(gApp.mSettings.mEditorSettings.mUIScale / 100.0f, true);
DeleteAndNullify!(gApp.mKeyChordState);
mKeySettings.Apply();
mDebuggerSettings.Apply();
mEditorSettings.Apply();
for (var window in gApp.mWindows)
{
if (var widgetWindow = window as WidgetWindow)
{
widgetWindow.mRootWidget.RehupSize();
}
}
if (!mWakaTimeKey.IsEmpty)
{
if (gApp.mWakaTime == null)
gApp.mWakaTime = new WakaTime(mWakaTimeKey);
}
else
{
DeleteAndNullify!(gApp.mWakaTime);
}
}
}
}

136
IDE/src/SimpleProgram.bf Normal file
View file

@ -0,0 +1,136 @@
#if false
using System;
using Beefy;
using Beefy.utils;
using System.Collections.Generic;
using Beefy.widgets;
using System.Diagnostics;
using Beefy.res;
using Beefy.gfx;
using Beefy.theme;
using Beefy.theme.dark;
namespace IDE
{
class Board : Widget
{
EditWidget mEditWidget ~ delete _;
public this()
{
ThemeFactory.mDefault = DarkTheme.Get();
mEditWidget = DarkTheme.sDarkTheme.CreateEditWidget(this, 5, 5, 400, 400);
mEditWidget.Content.mIsMultiline = true;
mEditWidget.Content.mWordWrap = false;
}
public override void Draw(Beefy.gfx.Graphics g)
{
base.Draw(g);
using (g.PushColor(0xFF000030))
g.FillRect(0, 0, mWidth, mHeight);
using (g.PushColor(0xFFFF0000))
g.FillRect(10 + (mUpdateCnt % 200), 10, 200, 200);
g.SetFont(IDEApp.sApp.mCodeFont);
g.DrawString("This is a test string", 50, 50);
}
public override void Update()
{
base.Update();
if ((mUpdateCnt % 100) == 0)
{
Debug.WriteLine("Tick: {0}", mUpdateCnt);
}
}
}
class IDEApp : BFApp
{
WidgetWindow mMainWindow ~ delete _;
Board mBoard ~ delete _;
public Font mCodeFont ~ delete _;
public new static IDEApp sApp;
public override void Init()
{
sApp = this;
base.Init();
mBoard = new Board();
mBoard.Resize(0, 0, 640, 480);
mMainWindow = new WidgetWindow(null, "Main Window", 64, 64, 640, 480,
BFWindowBase.Flags.Border | BFWindowBase.Flags.Caption | BFWindowBase.Flags.QuitOnClose | BFWindowBase.Flags.SysMenu | BFWindowBase.Flags.Minimize, mBoard);
String fileName = scope String();
fileName.Append(BFApp.sApp.mInstallDir, "fonts/SourceCodePro9.fnt");
mCodeFont = Font.LoadFromFile(fileName);
}
}
class Program
{
public static int Main(string[] args)
{
string testStr = scope String();
testStr.AppendF("0x{0:x}L", (long)0x123456789ABCDEF'UL);
IDEApp app = new IDEApp();
long val = long.Parse("ABC", System.Globalization.NumberStyles.HexNumber);
app.Init();
app.Run();
delete app;
/*StructuredData sd = StructuredData.LoadFromFile("c:/temp/test.json");
String str = stack String();
sd.GetString(str, "Hey");
delete sd;
//Object obj = null;
var outStr = stack String();
outStr.AppendF("A{0} B{1}", 123, "Yo");
string text = scope String();
Utils.LoadTextFile(text, "c:/temp/Test.txt");
//int[] intArr = stack {3, 6, 8};
Dictionary<int, float> testMap = new Dictionary<int, float>();
testMap[3] = 4.5f;
testMap[4] = 5.6f;
testMap[6] = 6.7f;
for (var pair in testMap)
{
var key = pair.Key;
var val = pair.Value;
//
}
{
int crap = 123;
}
float val = testMap[3];
(void)val;
val = testMap[4];
val = testMap[6];
PrintF("Hello!"); */
return 0;
}
}
}
#endif

33
IDE/src/SourceControl.bf Normal file
View file

@ -0,0 +1,33 @@
using System;
using System.Diagnostics;
using System.IO;
namespace IDE
{
class SourceControl
{
void DoP4Cmd(StringView fileName)
{
String actualFileName = scope String();
Path.GetActualPathName(fileName, actualFileName);
ProcessStartInfo psi = scope ProcessStartInfo();
psi.SetFileName("p4.exe");
var args = scope String();
args.AppendF("edit -c default \"{0}\"", actualFileName);
Debug.WriteLine("P4: {0}", args);
psi.SetArguments(args);
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
var process = scope SpawnedProcess();
process.Start(psi).IgnoreError();
process.WaitFor(-1);
}
public void Checkout(StringView fileName)
{
DoP4Cmd(fileName);
}
}
}

126
IDE/src/SpellChecker.bf Normal file
View file

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Beefy.utils;
namespace IDE
{
public class SpellChecker : CommandQueueManager
{
[StdCall, CLink]
static extern void* SpellChecker_Create(char8* langPath);
[StdCall, CLink]
static extern void SpellChecker_Delete(void* nativeSpellchecker);
[StdCall, CLink]
static extern bool SpellChecker_IsWord(void* nativeSpellchecker, char8* word);
[StdCall, CLink]
static extern void SpellChecker_AddWord(void* nativeSpellchecker, char8* word);
[StdCall, CLink]
static extern char8* SpellChecker_GetSuggestions(void* spellChecker, char8* word);
void* mNativeSpellChecker;
String[] mLangWordList = new String[] {
"int", "uint", "struct", "bool", "enum", "int", "proj", "newbox", "params", "typeof", "var"
} ~ delete _;
public String mLangPath ~ delete _;
public HashSet<String> mIgnoreWordList = new HashSet<String>() ~ DeleteContainerAndItems!(_);
public HashSet<String> mCustomDictionaryWordList = new HashSet<String>() ~ DeleteContainerAndItems!(_);
public this()
{
}
public Result<void> Init(String langPath)
{
scope AutoBeefPerf("SpellChecker.Init");
mLangPath = new String(langPath);
mNativeSpellChecker = SpellChecker_Create(langPath);
if (mNativeSpellChecker == null)
return .Err;
String fileName = scope String();
GetUserDirectFileName(fileName);
//if (File.ReadLines(fileName) case .Ok(var lineEnumeratorVal))
let streamReader = scope StreamReader();
if (streamReader.Open(fileName) case .Ok)
{
for (var wordResult in streamReader.Lines)
{
if (wordResult case .Err)
break;
AddWord(wordResult);
mCustomDictionaryWordList.Add(new String(wordResult));
}
}
for (var word in mLangWordList)
AddWord(word);
return .Ok;
}
public ~this()
{
CancelBackground();
SpellChecker_Delete(mNativeSpellChecker);
SaveWordList();
}
static void GetUserDirectFileName(String path)
{
path.Append(IDEApp.sApp.mInstallDir, "userdict.txt");
}
public static void ResetWordList()
{
String fileName = scope String();
GetUserDirectFileName(fileName);
File.Delete(fileName).IgnoreError();
}
protected override void DoProcessQueue()
{
}
public void SaveWordList()
{
String fileName = scope String();
GetUserDirectFileName(fileName);
File.WriteAllLines(fileName, mCustomDictionaryWordList.GetEnumerator());
}
public bool IsWord(String word)
{
return SpellChecker_IsWord(mNativeSpellChecker, word);
}
public void AddWord(StringView word)
{
SpellChecker_AddWord(mNativeSpellChecker, word.ToScopeCStr!());
}
public void GetSuggestions(String word, List<String> suggestions)
{
char8* result = SpellChecker_GetSuggestions(mNativeSpellChecker, word);
String resultStr = scope String(result);
var stringViews = scope List<StringView>(resultStr.Split('\n'));
for (var view in stringViews)
suggestions.Add(new String(view));
}
}
}

27
IDE/src/Targets.bf Normal file
View file

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace IDE
{
public class Targets
{
[StdCall, CLink]
static extern void Targets_Create();
[StdCall, CLink]
static extern void Targets_Delete();
public this()
{
Targets_Create();
}
public ~this()
{
Targets_Delete();
}
}
}

493
IDE/src/TestManager.bf Normal file
View file

@ -0,0 +1,493 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.IO;
namespace IDE
{
class TestManager
{
public class ProjectInfo
{
public Project mProject;
public String mTestExePath ~ delete _;
}
public class TestEntry
{
public String mName ~ delete _;
public String mFilePath ~ delete _;
public int mLine;
public int mColumn;
public bool mShouldFail;
public bool mProfile;
public bool mIgnore;
}
public class TestInstance
{
public SpawnedProcess mProcess ~ delete _;
public Thread mThread ~ delete _;
public int mProjectIdx;
public List<TestEntry> mTestEntries = new .() ~ DeleteContainerAndItems!(_);
public String mPipeName ~ delete _;
public String mArgs ~ delete _;
public String mWorkingDir ~ delete _;
public NamedPipe mPipeServer ~ delete _;
public int mShouldFailIdx = -1;
}
public bool mIsDone;
public bool mIsRunning;
public bool mWantsStop;
public int mProjectInfoIdx = -1;
public TestInstance mTestInstance ~ delete _;
public List<ProjectInfo> mProjectInfos = new .() ~ DeleteContainerAndItems!(_);
public List<String> mQueuedOutput = new .() ~ DeleteContainerAndItems!(_);
public Monitor mMonitor = new Monitor() ~ delete _;
public String mPrevConfigName ~ delete _;
public bool mDebug;
public bool mIncludeIgnored;
public bool mFailed;
public ~this()
{
if (mTestInstance != null)
{
mTestInstance.mThread.Join();
}
}
public bool IsRunning()
{
return true;
}
public void AddProject(Project project)
{
var projectInfo = new ProjectInfo();
projectInfo.mProject = project;
mProjectInfos.Add(projectInfo);
}
public bool IsTesting(Project project)
{
return GetProjectInfo(project) != null;
}
public ProjectInfo GetProjectInfo(Project project)
{
int projectIdx = mProjectInfos.FindIndex(scope (info) => info.mProject == project);
if (projectIdx == -1)
return null;
return mProjectInfos[projectIdx];
}
public void Start()
{
mIsRunning = true;
}
public void BuildFailed()
{
mIsDone = true;
}
ProjectInfo GetCurProjectInfo()
{
if ((mProjectInfoIdx >= 0) && (mProjectInfoIdx < mProjectInfos.Count))
return mProjectInfos[mProjectInfoIdx];
return null;
}
void QueueOutputLine(StringView str)
{
using (mMonitor.Enter())
mQueuedOutput.Add(new String(str));
}
void QueueOutputLine(StringView str, params Object[] args)
{
using (mMonitor.Enter())
{
var formattedStr = new String();
formattedStr.AppendF(str, params args);
mQueuedOutput.Add(formattedStr);
}
}
public void TestProc(TestInstance testInstance)
{
var curProjectInfo = GetCurProjectInfo();
if (!mDebug)
{
var startInfo = scope ProcessStartInfo();
startInfo.CreateNoWindow = !gApp.mTestEnableConsole;
startInfo.SetFileName(curProjectInfo.mTestExePath);
startInfo.SetArguments(testInstance.mArgs);
startInfo.SetWorkingDirectory(testInstance.mWorkingDir);
mTestInstance.mProcess = new SpawnedProcess();
if (testInstance.mProcess.Start(startInfo) case .Err)
{
TestFailed();
QueueOutputLine("ERROR: Failed execute '{0}'", curProjectInfo.mTestExePath);
return;
}
}
String clientStr = scope String();
int curTestIdx = -1;
int curTestRunCount = 0;
bool testsFinished = false;
bool failed = false;
int exitCode = 0;
while (true)
{
int doneCount = 0;
for (int itr < 2)
{
bool hadData = false;
uint8[1024] data;
switch (testInstance.mPipeServer.TryRead(.(&data, 1024), 20))
{
case .Ok(let size):
{
clientStr.Append((char8*)&data, size);
hadData = true;
}
default:
}
while (true)
{
int crPos = clientStr.IndexOf('\n');
if (crPos == -1)
break;
String cmd = scope String();
cmd.Append(clientStr, 0, crPos);
clientStr.Remove(0, crPos + 1);
/*String outStr = scope String();
outStr.AppendF("CMD: {0}", cmd);
QueueOutput(outStr);*/
List<StringView> cmdParts = scope .(cmd.Split('\t'));
switch (cmdParts[0])
{
case ":TestInit":
case ":TestBegin":
case ":TestQuery":
if ((curTestIdx == -1) || (curTestRunCount > 0))
{
curTestIdx++;
curTestRunCount = 0;
}
while (true)
{
if (curTestIdx < testInstance.mTestEntries.Count)
{
curTestRunCount++;
bool skipEntry = false;
let testEntry = testInstance.mTestEntries[curTestIdx];
if (testEntry.mShouldFail)
{
skipEntry = testInstance.mShouldFailIdx != curTestIdx;
}
else if (testInstance.mShouldFailIdx != -1)
{
skipEntry = true;
}
if ((!skipEntry) && (testEntry.mIgnore) && (!mIncludeIgnored))
{
QueueOutputLine("Test Ignored: {0}", testEntry.mName);
skipEntry = true;
}
if (skipEntry)
{
curTestIdx++;
curTestRunCount = 0;
continue;
}
var clientCmd = scope String();
clientCmd.AppendF(":TestRun\t{0}\n", curTestIdx);
if (testInstance.mPipeServer.Write(clientCmd) case .Err)
failed = true;
}
else
{
if (testInstance.mPipeServer.Write(":TestFinish\n") case .Err)
failed = true;
}
break;
}
case ":TestResult":
int timeMS = int32.Parse(cmdParts[1]).Get();
var testEntry = testInstance.mTestEntries[curTestIdx];
if (testEntry.mShouldFail)
{
QueueOutputLine("ERROR: Test should have failed but didn't: {0} Time: {1}ms", testEntry.mName, timeMS);
failed = true;
}
else
QueueOutputLine("Test completed: {0} Time: {1}ms", testEntry.mName, timeMS);
case ":TestFinish":
testsFinished = true;
default:
Debug.Assert(cmdParts[0][0] != ':');
let attribs = cmdParts[1];
TestEntry testEntry = new TestEntry();
testEntry.mName = new String(cmdParts[0]);
testEntry.mFilePath = new String(cmdParts[2]);
testEntry.mLine = int32.Parse(cmdParts[3]).Get();
testEntry.mColumn = int32.Parse(cmdParts[4]).Get();
testEntry.mShouldFail = attribs.Contains("Sf");
testEntry.mProfile = attribs.Contains("Pr");
testEntry.mIgnore = attribs.Contains("Ig");
testInstance.mTestEntries.Add(testEntry);
}
}
if (mWantsStop)
{
if (testInstance.mProcess != null)
testInstance.mProcess.Kill();
}
if (!hadData)
{
bool processDone;
if (testInstance.mProcess != null)
processDone = testInstance.mProcess.WaitFor(0);
else
processDone = !gApp.mDebugger.mIsRunning;
if (processDone)
{
if (testInstance.mProcess != null)
{
exitCode = testInstance.mProcess.ExitCode;
}
doneCount++;
}
}
}
if (doneCount == 2)
break;
if (failed)
{
TestFailed();
break;
}
}
if (mWantsStop)
{
QueueOutputLine("Tests aborted");
}
else if (!testsFinished)
{
var str = scope String();
if (curTestIdx == -1)
{
str.AppendF("Failed to start tests");
}
else if (curTestIdx < testInstance.mTestEntries.Count)
{
var testEntry = testInstance.mTestEntries[curTestIdx];
if (testInstance.mShouldFailIdx == curTestIdx)
{
// Success
QueueOutputLine("Test expectedly failed: {0}", testEntry.mName);
}
else
{
str.AppendF("ERROR: Failed test '{0}' at line {2}:{3} in {1}", testEntry.mName, testEntry.mFilePath, testEntry.mLine + 1, testEntry.mColumn + 1);
}
}
else
{
str.AppendF("ERROR: Failed to finish tests");
}
if (str.Length > 0)
{
var errStr = scope String();
errStr.AppendF("ERROR: {0}", str);
QueueOutputLine(errStr);
TestFailed();
}
}
else if (exitCode != 0)
{
if (exitCode != 0)
{
QueueOutputLine("ERROR: Test process exited with error code: {0}", exitCode);
TestFailed();
}
}
}
public void Update()
{
using (mMonitor.Enter())
{
while (mQueuedOutput.Count > 0)
{
var str = mQueuedOutput.PopFront();
gApp.OutputLineSmart(str);
delete str;
}
}
if ((!mIsRunning) || (mIsDone))
return;
if (mWantsStop)
{
if (gApp.mDebugger.mIsRunning)
gApp.mDebugger.Terminate();
}
int nextShouldFailIdx = -1;
bool doNext = true;
var curProjectInfo = GetCurProjectInfo();
if (curProjectInfo != null)
{
if (mTestInstance != null)
{
if (mTestInstance.mThread.Join(0))
{
for (int entryIdx = mTestInstance.mShouldFailIdx + 1; entryIdx < mTestInstance.mTestEntries.Count; entryIdx++)
{
let testEntry = mTestInstance.mTestEntries[entryIdx];
if (testEntry.mShouldFail)
{
nextShouldFailIdx = entryIdx;
break;
}
}
DeleteAndNullify!(mTestInstance);
}
else
doNext = false;
}
}
else
{
Debug.Assert(mTestInstance == null);
}
if (doNext)
{
if (mWantsStop)
{
mIsDone = true;
return;
}
Debug.Assert(mTestInstance == null);
if (nextShouldFailIdx == -1)
{
mProjectInfoIdx++;
if (mProjectInfoIdx >= mProjectInfos.Count)
{
mIsDone = true;
return;
}
}
mTestInstance = new TestInstance();
mTestInstance.mProjectIdx = mProjectInfoIdx;
mTestInstance.mShouldFailIdx = nextShouldFailIdx;
curProjectInfo = GetCurProjectInfo();
if (mTestInstance.mShouldFailIdx != -1)
gApp.OutputLineSmart("Starting should-fail testing on {0}...", curProjectInfo.mProject.mProjectName);
else
gApp.OutputLineSmart("Starting testing on {0}...", curProjectInfo.mProject.mProjectName);
mTestInstance.mThread = new Thread(new () => { TestProc(mTestInstance); } );
mTestInstance.mPipeName = new String();
mTestInstance.mPipeName.AppendF("__bfTestPipe{0}_{1}", Process.CurrentId, mTestInstance.mProjectIdx);
mTestInstance.mArgs = new String();
mTestInstance.mArgs.Append(mTestInstance.mPipeName);
//mTestInstance.mWorkingDir = new String();
//Path.GetDirectoryName(curProjectInfo.mTestExePath, mTestInstance.mWorkingDir);
mTestInstance.mWorkingDir = new String(gApp.mInstallDir);
mTestInstance.mPipeServer = new NamedPipe();
if (mTestInstance.mPipeServer.Create(".", mTestInstance.mPipeName, .AllowTimeouts) case .Err)
{
QueueOutputLine("ERROR: Failed to create named pipe for test");
TestFailed();
return;
}
if (mDebug)
{
gApp.[Friend]CheckDebugVisualizers();
var envVars = scope Dictionary<String, String>();
defer { for (var kv in envVars) { delete kv.key; delete kv.value; } }
Environment.GetEnvironmentVariables(envVars);
var envBlock = scope List<char8>();
Environment.EncodeEnvironmentVariables(envVars, envBlock);
if (!gApp.mDebugger.OpenFile(curProjectInfo.mTestExePath, mTestInstance.mArgs, mTestInstance.mWorkingDir, envBlock, true))
{
QueueOutputLine("ERROR: Failed debug '{0}'", curProjectInfo.mTestExePath);
TestFailed();
return;
}
gApp.mDebugger.ClearInvalidBreakpoints();
gApp.mTargetDidInitBreak = false;
gApp.mTargetHadFirstBreak = false;
gApp.mDebugger.RehupBreakpoints(true);
gApp.mDebugger.Run();
gApp.mDebugger.mIsRunning = true;
}
mTestInstance.mThread.Start(false);
}
}
public void TestFailed()
{
gApp.TestFailed();
mIsDone = true;
mFailed = true;
}
public void Stop()
{
mWantsStop = true;
}
}
}

295
IDE/src/WakaTime.bf Normal file
View file

@ -0,0 +1,295 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Beefy;
namespace IDE
{
public class WakaTime
{
String mApiKey ~ delete _;
String mPythonLocation ~ delete _;
String mCurFilePath = new String() ~ delete _;
int32 mLastSendTicks;
Monitor mMonitor = new Monitor() ~ delete _;
public this(String key)
{
mApiKey = new String(key);
}
public void Dispose()
{
}
public void QueueFile(String filePath, String projectName, bool isWrite)
{
String useFilePath = filePath;
String useProjectName = projectName;
bool doSend = false;
if (mCurFilePath != useFilePath)
{
doSend = true;
}
else if (mLastSendTicks > 120*60)
{
doSend = true;
}
if (isWrite)
doSend = true;
mCurFilePath.Set(useFilePath);
if (doSend)
{
useFilePath = new String(useFilePath);
useProjectName = new String(useProjectName);
var me = this;
ThreadPool.QueueUserWorkItem(new () => me.SendFile(useFilePath, useProjectName, isWrite) ~ { delete useFilePath; delete useProjectName; });
mLastSendTicks = 0;
}
}
public void Update()
{
mLastSendTicks++;
}
public void getPythonDir(String pyDir)
{
getCurrentDirectory(pyDir);
pyDir.Append("\\Python");
}
public void getPython(String outPath)
{
doesPythonExist();
//return;
if (mPythonLocation != null)
{
outPath.Append(mPythonLocation);
return;
}
String[] locations = scope
.(
//"c:\\Python27\\python.exe",
"pythonw.exe",
"python",
"\\Python37\\pythonw",
"\\Python36\\pythonw",
"\\Python35\\pythonw",
"\\Python34\\pythonw",
"\\Python33\\pythonw",
"\\Python32\\pythonw",
"\\Python31\\pythonw",
"\\Python30\\pythonw",
"\\Python27\\pythonw",
"\\Python26\\pythonw",
"\\python37\\pythonw",
"\\python36\\pythonw",
"\\python35\\pythonw",
"\\python34\\pythonw",
"\\python33\\pythonw",
"\\python32\\pythonw",
"\\python31\\pythonw",
"\\python30\\pythonw",
"\\python27\\pythonw",
"\\python26\\pythonw",
"\\Python37\\python",
"\\Python36\\python",
"\\Python35\\python",
"\\Python34\\python",
"\\Python33\\python",
"\\Python32\\python",
"\\Python31\\python",
"\\Python30\\python",
"\\Python27\\python",
"\\Python26\\python",
"\\python37\\python",
"\\python36\\python",
"\\python35\\python",
"\\python34\\python",
"\\python33\\python",
"\\python32\\python",
"\\python31\\python",
"\\python30\\python",
"\\python27\\python",
"\\python26\\python"
);
for (String location in locations)
{
if (location.Contains('\\'))
{
String dirName = scope String();
Path.GetDirectoryPath(location, dirName);
if (!Directory.Exists(dirName))
continue;
}
ProcessStartInfo procInfo = scope ProcessStartInfo();
procInfo.UseShellExecute = false;
procInfo.RedirectStandardError = true;
procInfo.RedirectStandardOutput = true;
procInfo.SetFileName(location);
procInfo.CreateNoWindow = true;
procInfo.SetArguments("--version");
Debug.WriteLine("ProcStartInfo {0} Verb: {1}", procInfo, procInfo.mVerb);
/*Process process = null;
if (!case .Ok(out process) = Process.Start(procInfo))
continue;
defer(scope) delete process;
String errors = scope String();
if (case .Err = process.StandardError.ReadToEnd(errors))
continue;*/
String resultStr = scope String();
SpawnedProcess process = scope SpawnedProcess();
if (process.Start(procInfo) case .Err)
continue;
FileStream fileStream = scope FileStream();
process.AttachStandardError(fileStream);
StreamReader streamReader = scope StreamReader(fileStream, null, false, 4096);
streamReader.ReadToEnd(resultStr).IgnoreError();
if (resultStr.IsEmpty)
{
FileStream fileStreamOut = scope FileStream();
process.AttachStandardOutput(fileStreamOut);
StreamReader streamReaderOut = scope StreamReader(fileStreamOut, null, false, 4096);
streamReaderOut.ReadToEnd(resultStr).IgnoreError();
}
//TODO: This 'errors' check is not correct, but also it seems that we're getting stdout data in stderr... (?)
if ((resultStr != null) && (resultStr != ""))
{
mPythonLocation = new String(location);
outPath.Append(mPythonLocation);
return;
}
}
mPythonLocation = new String("");// Give up
return;
}
void GetCLI(String cliPath)
{
cliPath.Append(BFApp.sApp.mInstallDir, "wakatime-master/wakatime/cli.py");
}
SpawnedProcess mProcess ~ delete _;
public void SendFile(String fileName, String projectName, bool isWrite)
{
using (mMonitor.Enter())
{
DoSendFile(fileName, projectName, isWrite);
}
}
public void DoSendFile(String fileName, String projectName, bool isWrite)
{
Debug.WriteLine("WakaTime: {0} proj: {1} isWrite: {2} ThreadId: {3} Tick: {4}", fileName, projectName, isWrite, Thread.CurrentThread.Id, (int32)Platform.BfpSystem_TickCount());
String arguments = scope String();
arguments.Append("\"");
GetCLI(arguments);
arguments.Append("\" --key=\"", mApiKey, "\"",
" --file=\"", fileName, "\"",
" --plugin=\"Beef\"");
if (!String.IsNullOrWhiteSpace(projectName))
arguments.Append(" --project=\"", projectName, "\"");
if (isWrite)
arguments.Append(" --write");
ProcessStartInfo procInfo = scope ProcessStartInfo();
procInfo.UseShellExecute = false;
String pyPath = scope String();
getPython(pyPath);
if (String.IsNullOrEmpty(pyPath))
return;
procInfo.SetFileName(pyPath);
procInfo.CreateNoWindow = true;
procInfo.SetArguments(arguments);
//for (int i = 0; i < 10; i++)
{
//Debug.WriteLine("ProcStartInfo {0} Dir: {1} Verb: {2}", procInfo, procInfo.mDirectory, procInfo.mVerb);
delete mProcess;
mProcess = new SpawnedProcess();
if (mProcess.Start(procInfo) case .Err)
{
delete mProcess;
mProcess = null;
}
}
}
/// Check if wakatime command line exists or not
bool doesCLIExist()
{
String path = scope String();
GetCLI(path);
if (File.Exists(path))
{
return true;
}
return false;
}
/// Check if bundled python installation exists
bool doesPythonExist()
{
String path = scope String();
getPythonDir(path);
path.Append("\\pythonw.exe");
if (File.Exists(path))
{
return true;
}
return false;
}
/// Check if python is installed
bool isPythonInstalled()
{
String pyPath = scope String();
getPython(pyPath);
if (String.IsNullOrEmpty(pyPath))
{
return true;
}
return false;
}
/// Returns current working dir
static public void getCurrentDirectory(String outDir)
{
var exePath = scope String();
Environment.GetExecutableFilePath(exePath);
Path.GetDirectoryPath(exePath, outDir);
}
}
}

1371
IDE/src/Workspace.bf Normal file

File diff suppressed because it is too large Load diff

166
IDE/src/ui/AboutDialog.bf Normal file
View file

@ -0,0 +1,166 @@
using Beefy.theme.dark;
using Beefy.gfx;
using System;
namespace IDE.ui
{
class AboutDialog : IDEDialog
{
const int cWidth = 320;
const int cHeight = 240;
const int cRandSize = 3777;
Font mBigFont ~ delete _;
Font mMedFont ~ delete _;
Image mImage ~ delete _;
uint32[256] mPalette;
uint8[cHeight][cWidth] mFire;
uint8[cRandSize] mRand;
int mRandIdx;
struct CColor
{
public uint8 r;
public uint8 g;
public uint8 b;
public uint8 a;
}
public this()
{
Title = "About Beef IDE";
mBigFont = new Font();
mBigFont.Load("Segoe UI", GS!(80.0f)); //8.8
mMedFont = new Font();
mMedFont.Load("Segoe UI", GS!(30.0f)); //8.8
mImage = Image.CreateDynamic((.)cWidth, (.)cHeight);
for (int x < cWidth)
{
mFire[cHeight-1][x] = 255;
}
Random rand = scope .(0xBEEF);
for (int i < cRandSize)
mRand[i] = (uint8)rand.NextI32();
uint32[6] mainColors =
.(
0x00000000,
0xFF000040,
0xFFFF0000,
0xFFFF8000,
0xFFFFFF00,
0xFFFFFFFF
);
for (int i < 256)
{
float colorPos = (i * 5 / 256.0f);
Color colorOut = Color.ToNative(Color.Lerp(mainColors[(int)colorPos], mainColors[(int)colorPos + 1], colorPos - (int)colorPos));
mPalette[i] = colorOut;
}
}
public override void CalcSize()
{
mWidth = GS!(640);
mHeight = GS!(480);
}
[Inline]
public uint8 GetRand()
{
return mRand[(mRandIdx++) % cRandSize];
}
public void DoFire()
{
for (int y = 1; y < cHeight; y++)
{
for (int x < cWidth)
{
uint8* src = &mFire[y][x];
uint8 pixel = *src;
if (pixel <= 8)
{
src[-cWidth] = 0;
continue;
}
uint8 randIdx = (uint8)GetRand();
uint8* ptr = &src[-cWidth - (randIdx & 3) + 1];
//uint8 randSub = (uint8)(randIdx & 7);
uint8 randSub = (uint8)(randIdx % 7);
*ptr = pixel - randSub;
}
}
/*for (int i < 10000)
{
uint8* src = &mFire[0][0];
int randOfs = (GetRand() * cWidth * (cHeight - 1)) / 256;
src[randOfs] = (uint8)((int)(src[randOfs] * 2) / 2 / 1);
}*/
}
public override void Draw(Graphics g)
{
using (g.PushColor(0xFF202020))
g.FillRect(0, 0, mWidth, mHeight);
if (mImage == null)
{
mImage = Image.CreateDynamic((.)mWidth, (.)mHeight);
}
uint32* newBits = new uint32[cWidth*cHeight]*;
defer delete newBits;
uint8* srcPtr = &mFire;
uint32* destPtr = newBits;
for (int y < cHeight)
{
for (int x < cWidth)
{
*(destPtr++) = mPalette[*(srcPtr++)];
}
}
mImage.SetBits(0, 0, cWidth, cHeight, cWidth, newBits);
float ang = Math.Min(mUpdateCnt * 0.006f, Math.PI_f / 2);
g.SetFont(mBigFont);
g.DrawString("Beef IDE", 0, GS!(20) + (1.0f - Math.Sin(ang))*GS!(300), .Centered, mWidth);
float angMed = Math.Min(mUpdateCnt * 0.0055f, Math.PI_f / 2);
float alpha = Math.Clamp(mUpdateCnt * 0.007f - 1.3f, 0, 1.0f);
g.SetFont(mMedFont);
using (g.PushColor(Color.Get(alpha)))
{
using (g.PushTranslate(0, (1.0f - Math.Sin(angMed))*GS!(200)))
{
g.DrawString("Copyright 2019 BeefyTech", 0, GS!(120), .Centered, mWidth);
}
}
g.DrawQuad(mImage, 0, 0, 0.0f, 0.0f, mWidth, mHeight, 1.0f, 1.0f);
}
public override void Update()
{
base.Update();
MarkDirty();
if (mRandIdx >= 0x4000'0000)
mRandIdx = 0;
DoFire();
}
}
}

324
IDE/src/ui/AttachDialog.bf Normal file
View file

@ -0,0 +1,324 @@
using System;
using System.Threading;
using System.Collections.Generic;
using Beefy.events;
using Beefy.widgets;
using Beefy.theme.dark;
using Beefy.gfx;
using Beefy.widgets;
using Beefy;
using System.Diagnostics;
namespace IDE.ui
{
class AttachDialog : DarkDialog
{
public static Dictionary<String, int32> sMRU = new Dictionary<String, int32>() ~ delete _;
public static int32 sCurrentMRUIndex = 1;
protected DarkListView mFileList;
EditWidget mEditWidget;
List<Process> mProcessList = new List<Process>() ~ delete _;
List<Process> mFullProcessList = new List<Process>() ~ DeleteContainerAndItems!(_);
public bool mFilterChanged;
public volatile bool mExitingThread;
public Thread mDateThread;
public int mDataAgeTicks;
public this()
{
mWindowFlags = BFWindow.Flags.ClientSized | BFWindow.Flags.TopMost | BFWindow.Flags.Caption |
BFWindow.Flags.Border | BFWindow.Flags.SysMenu | BFWindow.Flags.Resizable;
AddOkCancelButtons(new (evt) => { Attach(); }, null, 0, 1);
//mApplyButton = AddButton("Apply", (evt) => { evt.mCloseDialog = false; ApplyChanges(); });
Title = "Attach to Process";
mButtonBottomMargin = 6;
mButtonRightMargin = 6;
mFileList = new DarkListView();
mFileList.InitScrollbars(false, true);
mFileList.mAllowMultiSelect = false;
ListViewColumn column = mFileList.AddColumn(240, "Process");
column.mMinWidth = 100;
column = mFileList.AddColumn(80, "ID");
column = mFileList.AddColumn(200, "Title");
AddWidget(mFileList);
mTabWidgets.Add(mFileList);
mEditWidget = AddEdit("");
mEditWidget.mOnKeyDown.Add(new => EditKeyDownHandler);
mEditWidget.mOnContentChanged.Add(new (evt) => { mFilterChanged = true; });
}
Process GetSelectedProcess()
{
var root = mFileList.GetRoot();
var selectedListViewItem = root.FindFirstSelectedItem();
if (selectedListViewItem != null)
{
var itemIdx = root.mChildItems.IndexOf(selectedListViewItem);
var process = mProcessList[itemIdx];
return process;
}
return null;
}
void Attach()
{
var process = GetSelectedProcess();
if (process != null)
IDEApp.sApp.Attach(process, .None);
}
void EditKeyDownHandler(KeyDownEvent evt)
{
if ((evt.mKeyCode == KeyCode.Up) || (evt.mKeyCode == KeyCode.Down) || (evt.mKeyCode == KeyCode.PageUp) || (evt.mKeyCode == KeyCode.PageDown))
{
mFileList.KeyDown(evt.mKeyCode, false);
}
}
public void ValueClicked(MouseEvent theEvent)
{
DarkListViewItem clickedItem = (DarkListViewItem)theEvent.mSender;
DarkListViewItem item = (DarkListViewItem)clickedItem.GetSubItem(0);
mFileList.GetRoot().SelectItemExclusively(item);
mFileList.SetFocus();
/*if ((theEvent.mBtn == 0) && (theEvent.mBtnCount > 1))
{
for (int childIdx = 1; childIdx < mListView.GetRoot().GetChildCount(); childIdx++)
{
var checkListViewItem = mListView.GetRoot().GetChildAtIndex(childIdx);
checkListViewItem.IconImage = null;
}
int selectedIdx = item.mVirtualIdx;
IDEApp.sApp.mDebugger.mSelectedCallStackIdx = selectedIdx;
IDEApp.sApp.ShowPCLocation(selectedIdx, false, true);
IDEApp.sApp.StackPositionChanged();
}
UpdateIcons();*/
}
int CompareFileNames(StringView pathA, StringView pathB)
{
int pathStartA = pathA.LastIndexOf(IDEUtils.cNativeSlash);
int pathStartB = pathB.LastIndexOf(IDEUtils.cNativeSlash);
int lenA = pathA.Length - pathStartA - 1;
int lenB = pathB.Length - pathStartB - 1;
//int result = String.CompareOrdinal(pathA, pathStartA + 1, pathB, pathStartB + 1, Math.Min(lenA, lenB));
int result = String.Compare(pathA.Ptr + pathStartA + 1, lenA, pathB.Ptr + pathStartB + 1, Math.Min(lenA, lenB), false);
/*if (result == 0)
result = lenA - lenB;*/
return result;
}
void GetFullProcessList()
{
ClearAndDeleteItems(mFullProcessList);
mFullProcessList.Clear();
Process.GetProcesses(mFullProcessList);
}
void FilterProcesses(bool fullRefresh)
{
int selectedPid = -1;
if (Process selectedProcess = GetSelectedProcess())
selectedPid = selectedProcess.Id;
String filterString = scope String();
mEditWidget.GetText(filterString);
filterString.Trim();
double scrollPos = mFileList.mVertPos.v;
if ((mFullProcessList.Count == 0) || (fullRefresh))
{
GetFullProcessList();
}
mProcessList.Clear();
for (var process in mFullProcessList)
{
if (filterString.Length > 0)
{
var mainWindowTitle = scope String();
process.GetMainWindowTitle(mainWindowTitle);
if ((process.ProcessName.IndexOf(filterString, true) == -1) &&
(mainWindowTitle.IndexOf(filterString, true) == -1))
continue;
}
mProcessList.Add(process);
}
var root = mFileList.GetRoot();
root.Clear();
/*var selectedItem = null;// root.FindSelectedItem();
if ((selectedItem == null) && (root.GetChildCount() > 0))
{
selectedItem = root.GetChildAtIndex(0);
root.SelectItemExclusively(selectedItem);
}*/
mProcessList.Sort(scope (itemA, itemB) =>
{
int result = CompareFileNames(itemA.ProcessName, itemB.ProcessName);
if (result == 0)
return itemA.Id - itemB.Id;
return result;
});
for (var process in mProcessList)
{
var listViewItem = mFileList.GetRoot().CreateChildItem();
listViewItem.Label = process.ProcessName;
listViewItem.mOnMouseDown.Add(new => ValueClicked);
var subListViewItem = listViewItem.CreateSubItem(1);
var processIdStr = scope String();
process.Id.ToString(processIdStr);
subListViewItem.Label = processIdStr;
subListViewItem.mOnMouseDown.Add(new => ValueClicked);
subListViewItem = listViewItem.CreateSubItem(2);
var titleStr = scope String();
process.GetMainWindowTitle(titleStr);
subListViewItem.Label = titleStr;
subListViewItem.mOnMouseDown.Add(new => ValueClicked);
}
ListViewItem bestItem = null;
int32 bestPri = -1;
for (int32 childIdx = 0; childIdx < root.GetChildCount(); childIdx++)
{
var listViewItem = root.GetChildAtIndex(childIdx);
var process = mProcessList[childIdx];
if (process.Id == selectedPid)
{
bestPri = Int32.MaxValue;
bestItem = listViewItem;
}
var processName = scope String();
processName.Reference(process.ProcessName);
int32 pri;
sMRU.TryGetValue(processName, out pri);
if (pri > bestPri)
{
bestItem = listViewItem;
bestPri = pri;
}
}
mFileList.VertScrollTo(scrollPos);
if (bestItem != null)
{
mFileList.GetRoot().SelectItemExclusively(bestItem);
//mFileList.EnsureItemVisible(bestItem, true);
}
/*ShutdownThread();
mExitingThread = true;
mDateThread = new Thread(CheckFileDates);
mDateThread.Start();*/
}
void GotoFile()
{
var root = mFileList.GetRoot();
var selectedListViewItem = root.FindFirstSelectedItem();
if (selectedListViewItem != null)
{
//var itemIdx = root.mChildItems.IndexOf(selectedListViewItem);
//var projectSource = mProcessList[itemIdx];
//IDEApp.sApp.ShowProjectItem(projectSource);
//sMRU[projectSource.mPath] = sCurrentMRUIndex++;
}
}
public override void AddedToParent()
{
base.AddedToParent();
mEditWidget.SetFocus();
FilterProcesses(false);
}
public override void ResizeComponents()
{
base.ResizeComponents();
//var font = DarkTheme.sDarkTheme.mSmallFont;
mFileList.Resize(6, 6, mWidth - 6 - 6, mHeight - 20 - 6 - 20 - 6 - 6 - 6);
mEditWidget.Resize(6, mFileList.mY + mFileList.mHeight + 6, mWidth - 6 - 6, 20);
}
public override void CalcSize()
{
mWidth = 660;
mHeight = 512;
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
void Outline(Graphics g, Widget widget, int32 inflateX, int32 inflateY, uint32 color)
{
using (g.PushColor(color))
{
g.OutlineRect(widget.mX - inflateX, widget.mY - inflateY, widget.mWidth + inflateX * 2, widget.mHeight + inflateY * 2);
}
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
//Outline(g, mCategorySelector, 0, 0, 0xFF404040);
//Outline(g, mCategorySelector, -1, -1, 0xFF202020);
Outline(g, mFileList, 0, 0, IDEApp.cDialogOutlineLightColor);
Outline(g, mFileList, -1, -1, IDEApp.cDialogOutlineDarkColor);
}
void CheckFileDates()
{
//
}
public override void Update()
{
base.Update();
bool wantsFullRefresh = mDataAgeTicks == 40;
if ((mFilterChanged) || (wantsFullRefresh))
{
FilterProcesses(wantsFullRefresh);
mFilterChanged = false;
mDataAgeTicks = 0;
}
mDataAgeTicks++;
}
}
}

2340
IDE/src/ui/AutoComplete.bf Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,178 @@
using Beefy.utils;
using Beefy.theme.dark;
using Beefy.widgets;
namespace IDE.ui
{
class AutoCompletePanel : Panel
{
public class DataArea : DockedWidget
{
public AutoCompletePanel mPanel;
public void ResizeContent()
{
var autoComplete = mPanel.mAutoComplete;
if (autoComplete == null)
return;
float yOfs = 0;
if (autoComplete.mInvokeWidget != null)
{
/*float height = GS!(20);
mAutoComplete.mInvokeWidget.Resize(0, 2, mWidth, height);
yOfs += mAutoComplete.mInvokeWidget.mHeight;*/
autoComplete.mInvokeWidget.ResizeContent(false);
float height = autoComplete.mInvokeWidget.mHeight - GS!(12);
autoComplete.mInvokeWidget.Resize(GS!(0), GS!(2), mWidth, height);
yOfs += height;
}
if (autoComplete.mAutoCompleteListWidget != null)
{
autoComplete.mAutoCompleteListWidget.Resize(0, yOfs, mWidth, mHeight - yOfs);
autoComplete.mAutoCompleteListWidget.mScrollContent.mWidth = mWidth;
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeContent();
}
}
public class CommentArea : DockedWidget
{
public AutoCompletePanel mPanel;
public override void Draw(Beefy.gfx.Graphics g)
{
base.Draw(g);
var autoComplete = mPanel.mAutoComplete;
if (autoComplete == null)
return;
if (autoComplete.mAutoCompleteListWidget == null)
return;
if (autoComplete.mAutoCompleteListWidget.mSelectIdx == -1)
return;
if (autoComplete.mAutoCompleteListWidget.mDocumentationDelay > 0)
return;
var selectedEntry = autoComplete.mAutoCompleteListWidget.mEntryList[autoComplete.mAutoCompleteListWidget.mSelectIdx];
if (selectedEntry.mDocumentation == null)
return;
DocumentationParser docParser = scope .(selectedEntry.mDocumentation);
float drawX = GS!(6);
float drawY = GS!(4);
using (g.PushColor(0xFFC0C0C0))
g.DrawString(docParser.ShowDocString, drawX, drawY, .Left, mWidth - drawX - GS!(8), .Wrap);
}
public override void DrawAll(Beefy.gfx.Graphics g)
{
base.DrawAll(g);
using (g.PushColor(0x80FFFFFF))
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Bkg), 0, -GS!(6), mWidth, GS!(6));
}
}
public AutoComplete mAutoComplete;
public DarkDockingFrame mDockingFrame;
public DataArea mDataArea;
public CommentArea mCommentArea;
public this()
{
mDataArea = new .();
mDataArea.mPanel = this;
mDataArea.mIsFillWidget = true;
mCommentArea = new .();
mCommentArea.mPanel = this;
mCommentArea.mRequestedHeight = GS!(60);
mDockingFrame = new DarkDockingFrame();
mDockingFrame.mDrawBkg = false;
mDockingFrame.AddDockedWidget(mDataArea, null, .Top);
mDockingFrame.AddDockedWidget(mCommentArea, mDataArea, .Bottom);
AddWidget(mDockingFrame);
}
public bool Unbind(AutoComplete autoComplete)
{
if (mAutoComplete != autoComplete)
return false;
if ((mAutoComplete.mInvokeWidget != null) && (mAutoComplete.mInvokeWidget.mParent == mDataArea))
mDataArea.RemoveWidget(mAutoComplete.mInvokeWidget);
if ((mAutoComplete.mAutoCompleteListWidget != null) && (mAutoComplete.mAutoCompleteListWidget.mParent == mDataArea))
mDataArea.RemoveWidget(mAutoComplete.mAutoCompleteListWidget);
mAutoComplete = null;
return true;
}
public bool StartBind(AutoComplete autoComplete)
{
bool showInPanel = gApp.mSettings.mEditorSettings.mAutoCompleteShowKind == .Panel;
if (gApp.mSettings.mEditorSettings.mAutoCompleteShowKind == .PanelIfVisible)
showInPanel = mWidgetWindow != null;
if (!showInPanel)
{
if (mAutoComplete != null)
Unbind(mAutoComplete);
return false;
}
if (mAutoComplete == autoComplete)
return true;
if (mAutoComplete != null)
Unbind(mAutoComplete);
if (mWidgetWindow == null)
return false;
mAutoComplete = autoComplete;
return true;
}
public void FinishBind()
{
if (mAutoComplete == null)
return;
if ((mAutoComplete.mInvokeWidget != null) && (mAutoComplete.mInvokeWidget.mParent == null))
mDataArea.AddWidget(mAutoComplete.mInvokeWidget);
if ((mAutoComplete.mAutoCompleteListWidget != null) && (mAutoComplete.mAutoCompleteListWidget.mParent == null))
mDataArea.AddWidget(mAutoComplete.mAutoCompleteListWidget);
ResizeComponents();
if (mAutoComplete.mAutoCompleteListWidget != null)
mAutoComplete.mAutoCompleteListWidget.CenterSelection();
}
public void ResizeComponents()
{
mDockingFrame.Resize(0, 0, mWidth, mHeight);
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
public override void Serialize(StructuredData data)
{
data.Add("Type", "AutoCompletePanel");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
using Beefy.theme.dark;
namespace IDE.ui
{
class BoundCheckbox : DarkCheckBox
{
bool* mBoundValue;
public this(ref bool boundValue)
{
mBoundValue = &boundValue;
}
public override bool Checked
{
get
{
mState = *mBoundValue ? .Checked : .Unchecked;
//base.Checked = *mBoundValue;
return *mBoundValue;
}
set
{
*mBoundValue = value;
mState = *mBoundValue ? .Checked : .Unchecked;
}
}
public override void Update()
{
base.Update();
Checked = *mBoundValue;
}
}
}

View file

@ -0,0 +1,773 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Beefy.events;
using Beefy.gfx;
using Beefy.theme;
using Beefy.theme.dark;
using Beefy.utils;
using Beefy.widgets;
using IDE.Debugger;
using IDE.util;
using System.Diagnostics;
namespace IDE.ui
{
public class BreakpointListViewItem : DarkListViewItem
{
public Breakpoint mBreakpoint ~ _?.Deref();
public WatchRefreshButton mWatchRefreshButton;
public void Bind(Breakpoint breakpoint)
{
mBreakpoint?.Deref();
mBreakpoint = breakpoint;
mBreakpoint?.AddRef();
}
public override void Draw(Graphics g)
{
base.Draw(g);
if (mColumnIdx == 0)
{
if ((mBreakpoint != null) && (!mBreakpoint.mIsDead))
{
using (g.PushTranslate(6, 0))
mBreakpoint.Draw(g, false);
}
}
}
}
public class BreakpointListView : IDEListView
{
protected override ListViewItem CreateListViewItem()
{
DarkListViewItem anItem = new BreakpointListViewItem();
return anItem;
}
}
public class BreakpointPanel : Panel
{
public BreakpointListView mListView;
public bool mListDirty = true;
public bool mDeselectOnFocusLost = true;
public bool mHasPendingSelectionClear = false;
public String mPendingEvalStr ~ delete _;
public String mCurEvalExpr ~ delete _;
public Breakpoint mPendingMemoryBreakpoint ~ { if (_ != null) _.Deref(); };
public Action<int, int, String> mOnPendingMemoryBreakpoint ~ delete _;
public this()
{
mListView = new BreakpointListView();
mListView.mShowGridLines = true;
mListView.InitScrollbars(true, true);
mListView.mHorzScrollbar.mPageSize = GS!(100);
mListView.mHorzScrollbar.mContentSize = GS!(500);
mListView.mVertScrollbar.mPageSize = GS!(100);
mListView.mVertScrollbar.mContentSize = GS!(500);
mListView.UpdateScrollbars();
mListView.mOnMouseDown.Add(new => ListViewMouseDown);
mListView.mOnMouseClick.Add(new => ListViewClicked);
AddWidget(mListView);
ListViewColumn column = mListView.AddColumn(GS!(200), "Name");
column.mMinWidth = GS!(100);
column = mListView.AddColumn(GS!(80), "Tags");
column = mListView.AddColumn(GS!(200), "Condition");
column = mListView.AddColumn(GS!(200), "Hit Count");
column = mListView.AddColumn(GS!(200), "Logging");
IDEApp.sApp.mDebugger.mBreakpointsChangedDelegate.Add(new => BreakpointsChanged);
//RebuildUI();
SetScaleData();
}
void SetScaleData()
{
mListView.mIconX = GS!(4);
mListView.mOpenButtonX = GS!(4);
mListView.mLabelX = GS!(30);
mListView.mChildIndent = GS!(16);
mListView.mHiliteOffset = GS!(-2);
}
public override void RehupScale(float oldScale, float newScale)
{
base.RehupScale(oldScale, newScale);
SetScaleData();
}
public override void FocusForKeyboard()
{
base.FocusForKeyboard();
Update();
SetFocus();
if ((mListView.GetRoot().FindFocusedItem() == null) && (mListView.GetRoot().GetChildCount() > 0))
{
mListView.GetRoot().GetChildAtIndex(0).Focused = true;
}
}
public void BreakpointsChanged()
{
mListDirty = true;
}
public void MarkStatsDirty()
{
// We only need to really refresh the hit count...
mListDirty = true;
}
public override void Serialize(StructuredData data)
{
base.Serialize(data);
data.Add("Type", "BreakpointPanel");
}
public override bool Deserialize(StructuredData data)
{
return base.Deserialize(data);
}
public void ConfigureBreakpoint(Breakpoint breakpoint, String condition, int threadId, String logging, bool breakAfterLogging, int targetHitCount, Breakpoint.HitCountBreakKind hitCountBreakKind)
{
/*for (int itemIdx < mListView.GetRoot().GetChildCount())
{
var listViewItem = (BreakpointListViewItem)mListView.GetRoot().GetChildAtIndex(itemIdx);
if (listViewItem.Selected)
{
var subItem = listViewItem.GetSubItem(2);
subItem.Label = condition;
listViewItem.mBreakpoint.SetCondition(condition);
listViewItem.mBreakpoint.SetThreadId(threadId);
listViewItem.mBreakpoint.SetLogging(logging, breakAfterLogging);
listViewItem.mBreakpoint.SetHitCountTarget(targetHitCount, hitCountBreakKind);
BreakpointsChanged();
}
}
gApp.MarkDirty();*/
breakpoint.SetCondition(condition);
breakpoint.SetThreadId(threadId);
breakpoint.SetLogging(logging, breakAfterLogging);
breakpoint.SetHitCountTarget(targetHitCount, hitCountBreakKind);
BreakpointsChanged();
gApp.MarkDirty();
}
public void ClearHitCounts()
{
mListView.GetRoot().WithSelectedItems(scope (item) =>
{
var listViewItem = (BreakpointListViewItem)item;
listViewItem.mBreakpoint.ClearHitCount();
mListDirty = true;
});
gApp.MarkDirty();
}
public void SetBreakpointDisabled(bool disabled)
{
mListView.GetRoot().WithSelectedItems(scope (item) =>
{
var listViewItem = (BreakpointListViewItem)item;
if (listViewItem.Selected)
{
gApp.mDebugger.SetBreakpointDisabled(listViewItem.mBreakpoint, disabled);
if (!disabled)
{
}
BreakpointsChanged();
gApp.MarkDirty();
}
});
gApp.MarkDirty();
}
public void DeleteBreakpoint()
{
mListView.GetRoot().WithSelectedItems(scope (item) =>
{
var listViewItem = (BreakpointListViewItem)item;
if (listViewItem.Selected)
{
gApp.mDebugger.DeleteBreakpoint(listViewItem.mBreakpoint);
BreakpointsChanged();
}
});
gApp.MarkDirty();
}
public void BindToThread()
{
int activeThreadId = gApp.mDebugger.GetActiveThread();
if (activeThreadId <= 0)
return;
mListView.GetRoot().WithSelectedItems(scope (item) =>
{
var listViewItem = (BreakpointListViewItem)item;
listViewItem.mBreakpoint.SetThreadId(activeThreadId);
mListDirty = true;
});
gApp.MarkDirty();
}
public void ConfigureBreakpoints(Widget relWidget)
{
mListView.GetRoot().WithSelectedItems(scope (item) =>
{
var listViewItem = (BreakpointListViewItem)item;
if (listViewItem.Selected)
{
mDeselectOnFocusLost = false;
ConditionDialog dialog = new ConditionDialog();
dialog.Init(listViewItem.mBreakpoint);
dialog.PopupWindow(relWidget.mWidgetWindow);
mDeselectOnFocusLost = true;
}
});
}
public void AddMemoryBreakpoint(WidgetWindow window)
{
NewBreakpointDialog dialog = new .(.Memory);
dialog.Init();
dialog.PopupWindow(window);
}
public void AddSymbolBreakpoint(WidgetWindow window)
{
NewBreakpointDialog dialog = new .(.Symbol);
dialog.Init();
dialog.PopupWindow(window);
}
public MenuWidget ShowRightClickMenu(Widget relWidget, float x, float y, bool isSpecific)
{
//mSelectedParentItem = (DarkListViewItem)GetSelectedParentItem();
mDeselectOnFocusLost = false;
defer:: { mDeselectOnFocusLost = true; }
Menu menu = new Menu();
Menu menuItem;
Breakpoint firstSelectedBreakpoint = null;
bool selectedEnabledBreakpoint = false;
bool selectedDisabledBreakpoint = false;
mListView.GetRoot().WithSelectedItems(scope [&] (listViewItem) =>
{
var breakpointListViewItem = (BreakpointListViewItem)listViewItem;
var breakpoint = breakpointListViewItem.mBreakpoint;
if (firstSelectedBreakpoint == null)
firstSelectedBreakpoint = breakpoint;
selectedEnabledBreakpoint |= !breakpoint.mDisabled;
selectedDisabledBreakpoint |= breakpoint.mDisabled;
});
if (firstSelectedBreakpoint != null)
{
menuItem = menu.AddItem("Configure Breakpoint");
menuItem.mOnMenuItemSelected.Add(new (evt) =>
{
ConfigureBreakpoints(relWidget);
});
menuItem = menu.AddItem("Delete Breakpoint");
menuItem.mOnMenuItemSelected.Add(new (evt) =>
{
DeleteBreakpoint();
});
if (selectedEnabledBreakpoint)
{
menuItem = menu.AddItem("Disable Breakpoint");
menuItem.mOnMenuItemSelected.Add(new (evt) => { SetBreakpointDisabled(true); });
}
if (selectedDisabledBreakpoint)
{
menuItem = menu.AddItem("Enable Breakpoint");
menuItem.mOnMenuItemSelected.Add(new (evt) => { SetBreakpointDisabled(false); });
}
if (gApp.mDebugger.IsPaused())
{
menuItem = menu.AddItem("Bind to Current Thread");
menuItem.mOnMenuItemSelected.Add(new (evt) => { BindToThread(); });
gApp.MarkDirty();
}
}
if (!isSpecific)
{
if (gApp.mDebugger.IsPaused())
{
if (firstSelectedBreakpoint != null)
menu.AddItem();
menuItem = menu.AddItem("Add Memory Breakpoint");
menuItem.mOnMenuItemSelected.Add(new (evt) =>
{
AddMemoryBreakpoint(relWidget.mWidgetWindow);
});
}
menuItem = menu.AddItem("Add Symbol Breakpoint");
menuItem.mOnMenuItemSelected.Add(new (evt) =>
{
AddSymbolBreakpoint(relWidget.mWidgetWindow);
});
}
if (menu.mItems.IsEmpty)
{
delete menu;
return null;
}
MenuWidget menuWidget = ThemeFactory.mDefault.CreateMenuWidget(menu);
menuWidget.Init(relWidget, x, y);
return menuWidget;
//menuWidget.mWidgetWindow.mWindowClosedHandler += DeselectFolder;
}
protected override void ShowRightClickMenu(Widget relWidget, float x, float y)
{
ShowRightClickMenu(mListView.GetRoot(), x, y, false);
}
public void ListViewItemMouseDown(MouseEvent theEvent)
{
var clickedItem = (BreakpointListViewItem)theEvent.mSender;
var item = (BreakpointListViewItem)clickedItem.GetSubItem(0);
if (theEvent.mBtn == 1)
{
if (!item.Selected)
mListView.GetRoot().SelectItem(item, true);
}
else
mListView.GetRoot().SelectItem(item, true);
SetFocus();
if ((theEvent.mBtn == 0) && (theEvent.mBtnCount == 2))
{
var breakpoint = item.mBreakpoint;
if (breakpoint.mFileName != null)
{
gApp.RecordHistoryLocation();
gApp.ShowSourceFileLocation(breakpoint.mFileName, -1, -1, breakpoint.mLineNum, breakpoint.mColumn, LocatorType.Always, true);
}
}
/*if ((theEvent.mBtn == 0) && (theEvent.mBtnCount > 1))
{
for (int childIdx = 1; childIdx < mListView.GetRoot().GetChildCount(); childIdx++)
{
var checkListViewItem = mListView.GetRoot().GetChildAtIndex(childIdx);
checkListViewItem.IconImage = null;
}
int selectedIdx = item.mVirtualIdx;
IDEApp.sApp.mDebugger.mSelectedCallStackIdx = selectedIdx;
IDEApp.sApp.ShowPCLocation(selectedIdx, false, true);
IDEApp.sApp.StackPositionChanged();
}*/
}
void ListViewItemClicked(MouseEvent theEvent)
{
var anItem = (BreakpointListViewItem)theEvent.mSender;
if (anItem.mColumnIdx != 0)
anItem = (BreakpointListViewItem)anItem.GetSubItem(0);
if (theEvent.mBtn == 1)
{
float aX, aY;
theEvent.GetRootCoords(out aX, out aY);
ShowRightClickMenu(mWidgetWindow.mRootWidget, aX, aY, false);
}
else
{
//if (anItem.IsParent)
//anItem.Selected = false;
}
}
void ListViewMouseDown(MouseEvent theEvent)
{
mListView.GetRoot().WithSelectedItems(scope (item) => { item.Selected = false; });
}
void ListViewClicked(MouseEvent theEvent)
{
if (theEvent.mBtn == 1)
{
float aX, aY;
theEvent.GetRootCoords(out aX, out aY);
ShowRightClickMenu(mWidgetWindow.mRootWidget, aX, aY, false);
}
}
public enum MemoryBreakpointResult
{
Failure,
Success,
Pending
}
void PendingExprDone(String result)
{
int addr = 0;
int32 byteCount = 0;
String addrType = scope .();
if (result != null)
{
if (HandleMemoryBreakpointResult(mPendingEvalStr, result, out addr, out byteCount, addrType))
{
}
}
mOnPendingMemoryBreakpoint(addr, byteCount, addrType);
DeleteAndNullify!(mOnPendingMemoryBreakpoint);
DeleteAndNullify!(mPendingEvalStr);
}
void ExistingPendingExprDone(int addr, int byteCount, String addrType)
{
if (!mPendingMemoryBreakpoint.mIsDead)
{
if (addr != 0)
SetMemoryBreakpoint(mPendingMemoryBreakpoint, addr, byteCount, addrType);
}
mPendingMemoryBreakpoint.Deref();
mPendingMemoryBreakpoint = null;
}
public void CancelPending()
{
DeleteAndNullify!(mPendingEvalStr);
DeleteAndNullify!(mOnPendingMemoryBreakpoint);
if (mPendingMemoryBreakpoint != null)
{
mPendingMemoryBreakpoint.Deref();
mPendingMemoryBreakpoint = null;
}
DeleteAndNullify!(gApp.mPendingDebugExprHandler);
}
public bool HandleMemoryBreakpointResult(String evalStr, String val, out int addr, out int32 byteCount, String addrType)
{
if (val.StartsWith("!", StringComparison.Ordinal))
{
String errorString = scope String();
DebugManager.GetFailString(val, evalStr, errorString);
IDEApp.sApp.Fail(errorString);
return false;
}
var vals = scope List<StringView>(val.Split('\n'));
addr = (int)int64.Parse(scope String(vals[0]), System.Globalization.NumberStyles.HexNumber);
byteCount = int32.Parse(scope String(vals[1]));
addrType.Append(vals[2]);
return true;
}
public MemoryBreakpointResult TryCreateMemoryBreakpoint(String evalStr, out int addr, out int32 byteCount, String addrType, Action<int, int, String> pendingHandler)
{
addr = 0;
byteCount = 0;
String val = scope String();
//gApp.mDebugger.Evaluate(evalStr, val, -1);
let result = gApp.DebugEvaluate(null, evalStr, val, -1, .NotSet, .MemoryWatch | .AllowSideEffects | .AllowCalls, new => PendingExprDone);
if (result == .Pending)
{
Debug.Assert(mOnPendingMemoryBreakpoint == null);
mOnPendingMemoryBreakpoint = pendingHandler;
mPendingEvalStr = new String(evalStr);
return .Pending;
}
delete pendingHandler;
return HandleMemoryBreakpointResult(evalStr, val, out addr, out byteCount, addrType) ? .Success : .Failure;
}
void DoCreateMemoryBreakpoint(int addr, int byteCount, String addrType)
{
if (addr != 0)
{
gApp.RefreshWatches();
var breakpoint = gApp.mDebugger.CreateMemoryBreakpoint(mCurEvalExpr, addr, byteCount, addrType);
if (!breakpoint.IsBound())
{
ShowMemoryBreakpointError();
gApp.mDebugger.DeleteBreakpoint(breakpoint);
}
else
breakpoint.mDeleteOnUnbind = true;
}
DeleteAndNullify!(mCurEvalExpr);
}
public void CreateMemoryBreakpoint(String evalStr)
{
if (mCurEvalExpr != null)
{
gApp.Fail("Already creating memory breakpoint");
return;
}
int addr = 0;
int32 byteCount = 0;
String addrType = scope String();
switch (gApp.mBreakpointPanel.TryCreateMemoryBreakpoint(evalStr, out addr, out byteCount, addrType, new => DoCreateMemoryBreakpoint))
{
case .Pending:
mCurEvalExpr = new String(evalStr);
return;
case .Failure:
//gApp.Fail("Failed to evaluate to memory address");
return;
case .Success:
mCurEvalExpr = new String(evalStr);
}
DoCreateMemoryBreakpoint(addr, byteCount, addrType);
MarkDirty();
gApp.RefreshWatches();
}
public void ShowMemoryBreakpointError()
{
IDEApp.sApp.Fail("The breakpoint cannot be set. The maximum number of data breakpoints have already been set.");
}
void SetMemoryBreakpoint(Breakpoint breakpoint, int addr, int byteCount, String addrType)
{
gApp.RefreshWatches();
breakpoint.MoveMemoryBreakpoint((int)addr, byteCount, addrType);
if (!breakpoint.IsBound())
ShowMemoryBreakpointError();
BreakpointsChanged();
}
public void RefreshBreakpoint(BreakpointListViewItem listViewItem)
{
//
if (!IDEApp.sApp.mDebugger.mIsRunning)
return; // Fail
var breakpoint = listViewItem.mBreakpoint;
int addr;
int32 byteCount;
String addrType = scope String();
switch (TryCreateMemoryBreakpoint(listViewItem.mBreakpoint.mMemoryWatchExpression, out addr, out byteCount, addrType, new => ExistingPendingExprDone))
{
case .Failure:
return;
case .Success:
case .Pending:
Debug.Assert(mPendingMemoryBreakpoint == null);
mPendingMemoryBreakpoint = breakpoint;
mPendingMemoryBreakpoint.AddRef();
return;
}
//if (newBreakpoint == null)
//return;
SetMemoryBreakpoint(breakpoint, addr, byteCount, addrType);
}
public void SelectBreakpoints(HashSet<Breakpoint> breakpoints)
{
mListView.GetRoot().WithItems(scope (listViewItem) =>
{
var breakListViewItem = (BreakpointListViewItem)listViewItem;
breakListViewItem.Selected = breakpoints.Contains(breakListViewItem.mBreakpoint);
if (breakListViewItem.Selected)
{
if (mWidgetWindow != null)
mListView.EnsureItemVisible(breakListViewItem, false);
}
});
mHasPendingSelectionClear = true;
}
public void Populate()
{
var root = mListView.GetRoot();
var debugger = IDEApp.sApp.mDebugger;
while (root.GetChildCount() > debugger.mBreakpointList.Count)
{
root.RemoveChildItemAt(debugger.mBreakpointList.Count);
}
for (int32 breakIdx = 0; breakIdx < debugger.mBreakpointList.Count; breakIdx++)
{
var breakpoint = debugger.mBreakpointList[breakIdx];
if (breakIdx >= root.GetChildCount())
{
var newItem = root.CreateChildItem();
newItem.mOnMouseDown.Add(new => ListViewItemMouseDown);
newItem.mOnMouseClick.Add(new => ListViewItemClicked);
var subItem = newItem.CreateSubItem(1);
subItem.mOnMouseDown.Add(new => ListViewItemMouseDown);
subItem.mOnMouseClick.Add(new => ListViewItemClicked);
subItem = newItem.CreateSubItem(2);
subItem.mOnMouseDown.Add(new => ListViewItemMouseDown);
subItem.mOnMouseClick.Add(new => ListViewItemClicked);
subItem = newItem.CreateSubItem(3);
subItem.mOnMouseDown.Add(new => ListViewItemMouseDown);
subItem.mOnMouseClick.Add(new => ListViewItemClicked);
subItem = newItem.CreateSubItem(4);
subItem.mOnMouseDown.Add(new => ListViewItemMouseDown);
subItem.mOnMouseClick.Add(new => ListViewItemClicked);
}
var listViewItem = (BreakpointListViewItem)root.GetChildAtIndex(breakIdx);
listViewItem.mTextColor = Color.White;
listViewItem.mIsBold = breakpoint.IsActiveBreakpoint();
var locString = scope String();
breakpoint.ToString_Location(locString);
listViewItem.Label = locString;
if (breakpoint.IsBound())
listViewItem.mTextColor = 0xFFFFFFFF;
else
listViewItem.mTextColor = 0x80FFFFFF;
// Condition
var subItem = listViewItem.GetSubItem(2);
if (breakpoint == gApp.mDebugger.mRunToCursorBreakpoint)
subItem.Label = "Run to cursor";
else if (breakpoint.mCondition != null)
subItem.Label = breakpoint.mCondition;
else
subItem.Label = "";
// Hit count
subItem = listViewItem.GetSubItem(3);
let hitCountLabel = scope String();
breakpoint.ToString_HitCount(hitCountLabel);
subItem.Label = hitCountLabel;
// Logging
subItem = listViewItem.GetSubItem(4);
if (breakpoint.mLogging != null)
subItem.Label = breakpoint.mLogging;
else
subItem.Label = "";
listViewItem.Bind(breakpoint);
if (breakpoint.mIsMemoryBreakpoint && (!breakpoint.IsBound()))
{
if (listViewItem.mWatchRefreshButton == null)
{
var watchRefreshButton = new WatchRefreshButton();
watchRefreshButton.Resize(GS!(-16), 0, GS!(20), GS!(20));
watchRefreshButton.mOnMouseDown.Add(new (evt) => RefreshBreakpoint(listViewItem));
var typeSubItem = listViewItem.GetSubItem(1);
typeSubItem.AddWidget(watchRefreshButton);
listViewItem.mWatchRefreshButton = watchRefreshButton;
listViewItem.mTextAreaLengthOffset = -16;
}
}
else if (listViewItem.mWatchRefreshButton != null)
{
listViewItem.mTextAreaLengthOffset = 0;
defer delete listViewItem.mWatchRefreshButton;
listViewItem.mWatchRefreshButton.RemoveSelf();
listViewItem.mWatchRefreshButton = null;
}
/*else if (breakpoint.GetAddress() != 0)
listViewItem.Label = String.Format("{0}", Path.GetFileName(breakpoint.mFileName), breakpoint.mLineNum);*/
}
}
public override void Update()
{
base.Update();
if (mListDirty)
{
Populate();
mListDirty = false;
}
if ((mHasPendingSelectionClear) && (!mHasFocus) && (!gApp.HasPopupMenus()) && (!gApp.HasModalDialogs()))
{
// Don't clear focus if there's a dialog or something else with focus
mListView.GetRoot().SelectItemExclusively(null);
mHasPendingSelectionClear = false;
}
if (mWidgetWindow == null)
{
mListView.mListSizeDirty = true;
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
mListView.Resize(0, 0, width, height);
mListView.ScrollPositionChanged();
}
public override void KeyDown(KeyCode keyCode, bool isRepeat)
{
mListView.KeyDown(keyCode, isRepeat);
base.KeyDown(keyCode, isRepeat);
switch (keyCode)
{
case .Apps:
ShowRightClickMenu(mListView);
case KeyCode.Delete:
mListView.GetRoot().WithSelectedItems(scope (listViewItem) =>
{
var breakpointListViewItem = (BreakpointListViewItem)listViewItem;
BfLog.LogDbg("Manually deleting breakpoint\n");
IDEApp.sApp.mDebugger.DeleteBreakpoint(breakpointListViewItem.mBreakpoint);
});
default:
}
}
public override void LostFocus()
{
base.LostFocus();
if (mDeselectOnFocusLost)
mListView.GetRoot().SelectItemExclusively(null);
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
}
}
}

View file

@ -0,0 +1,306 @@
using System;
using System.Collections.Generic;
using Beefy.widgets;
using Beefy.theme.dark;
using Beefy.theme;
namespace IDE.ui
{
class BuildPropertiesDialog : TargetedPropertiesDialog
{
protected class DistinctOptionBuilder
{
BuildPropertiesDialog mDialog;
public this(BuildPropertiesDialog dialog)
{
mDialog = dialog;
}
class TypeOptionsEntry
{
public String mConfigName;
public String mPlatformName;
public List<DistinctBuildOptions> mPropTargets = new .() ~ delete _;
}
List<String> mTypeOptionsNames = new .() ~ delete _;
Dictionary<String, TypeOptionsEntry> mTypeOptionsDict = new .() ~ delete _;
public int mPropCount;
public void Add(List<DistinctBuildOptions> distinctBuildOptions)
{
int propIdx = mPropCount;
mPropCount++;
for (int typeOptionIdx < distinctBuildOptions.Count)
{
var typeOptions = distinctBuildOptions[typeOptionIdx];
if (typeOptions.mCreateState == .Deleted)
continue;
String* keyPtr;
TypeOptionsEntry* typeOptionsPtr;
TypeOptionsEntry typeOptionsEntry;
if (mTypeOptionsDict.TryAdd(typeOptions.mFilter, out keyPtr, out typeOptionsPtr))
{
mTypeOptionsNames.Add(typeOptions.mFilter);
typeOptionsEntry = new TypeOptionsEntry();
*typeOptionsPtr = typeOptionsEntry;
}
else
{
typeOptionsEntry = *typeOptionsPtr;
}
typeOptionsEntry.mConfigName = mDialog.[Friend]mConfigNames[propIdx / mDialog.[Friend]mPlatformNames.Count];
typeOptionsEntry.mPlatformName = mDialog.[Friend]mPlatformNames[propIdx % mDialog.[Friend]mPlatformNames.Count];
typeOptionsEntry.mPropTargets.Add(typeOptions);
}
}
public void Finish()
{
var root = (DarkListViewItem)mDialog.[Friend]mPropPage.mPropertiesListView.GetRoot();
let configNames = mDialog.[Friend]mConfigNames;
let platformNames = mDialog.[Friend]mPlatformNames;
for (var typeOptionsName in mTypeOptionsNames)
{
var typeOptionsEntry = mTypeOptionsDict[typeOptionsName];
var prevPropTargets = mDialog.[Friend]mCurPropertiesTargets;
mDialog.[Friend]mCurPropertiesTargets = null;
defer { mDialog.[Friend]mCurPropertiesTargets = prevPropTargets; }
mDialog.[Friend]mCurPropertiesTargets = scope Object[typeOptionsEntry.mPropTargets.Count];
for (int i < typeOptionsEntry.mPropTargets.Count)
mDialog.[Friend]mCurPropertiesTargets[i] = typeOptionsEntry.mPropTargets[i];
String label = scope .("Distinct Build Options");
if (typeOptionsEntry.mPropTargets.Count < configNames.Count * platformNames.Count)
{
if (typeOptionsEntry.mPropTargets.Count > 1)
label.Append(" <Multiple>");
else if ((configNames.Count > 1) && (platformNames.Count > 1))
label.AppendF(" ({0}/{1})", configNames[0], platformNames[1]);
else if (configNames.Count > 1)
label.AppendF(" ({0})", configNames[0]);
else
label.AppendF(" ({0})", platformNames[0]);
}
let (category, propEntry) = mDialog.[Friend]AddPropertiesItem(root, label, "mFilter");
mDialog.[Friend]SetupDistinctBuildOptions(propEntry);
mDialog.[Friend]AddDistinctBuildOptions(category, -1, true);
delete typeOptionsEntry;
}
}
}
protected List<Object> mDeferredDeleteList = new .() ~
{
for (let obj in _)
{
delete obj;
}
delete _;
};
protected void AddDistinctBuildOptions(DarkListViewItem category, int typeOptionIdx, bool isNew)
{
String optionsName = "";
String typeName = scope String();
if (!isNew)
{
typeName.Clear(); typeName.Append(optionsName, "mFilter");
let propEntry = SetupPropertiesItem(category, "Filter", typeName);
SetupDistinctBuildOptions(propEntry);
}
typeName.Clear(); typeName.Append(optionsName, "mBfSIMDSetting");
AddPropertiesItem(category, "SIMD Instructions", typeName);
typeName.Clear(); typeName.Append(optionsName, "mBfOptimizationLevel");
AddPropertiesItem(category, "Optimization Level", typeName);
typeName.Clear(); typeName.Append(optionsName, "mEmitDebugInfo");
AddPropertiesItem(category, "Debug Info", typeName);
typeName.Clear(); typeName.Append(optionsName, "mRuntimeChecks");
AddPropertiesItem(category, "Runtime Checks", typeName,
scope String[] { "No", "Yes" });
typeName.Clear(); typeName.Append(optionsName, "mEmitDynamicCastCheck");
AddPropertiesItem(category, "Dynamic Cast Check", typeName,
scope String[] { "No", "Yes" });
typeName.Clear(); typeName.Append(optionsName, "mEmitObjectAccessCheck");
AddPropertiesItem(category, "Object Access Check", typeName,
scope String[] { "No", "Yes" });
typeName.Clear(); typeName.Append(optionsName, "mAllocStackTraceDepth");
AddPropertiesItem(category, "Alloc Stack Trace Depth", typeName);
category.Open(true, true);
}
protected virtual Object[] PhysAddNewDistinctBuildOptions()
{
return null;
}
protected void AddNewDistinctBuildOptions()
{
var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot();
var (category, propEntry) = AddPropertiesItem(root, "Distinct Build Options");
var subItem = (DarkListViewItem)category.CreateSubItem(1);
subItem.mTextColor = 0xFFC0C0C0;
subItem.Label = "<Add New>...";
subItem.mOnMouseDown.Add(new (evt) =>
{
if (category.GetChildCount() != 0)
{
return;
}
subItem.Label = "";
let typeOptionsTargets = PhysAddNewDistinctBuildOptions();
defer delete typeOptionsTargets;
var prevTargets = mCurPropertiesTargets;
defer { mCurPropertiesTargets = prevTargets; }
mCurPropertiesTargets = typeOptionsTargets;
AddDistinctBuildOptions(category, -1, false);
AddNewDistinctBuildOptions();
});
category.mIsBold = true;
category.mTextColor = cHeaderColor;
}
protected void DeleteDistinctBuildOptions(DarkListViewItem listViewItem)
{
mPropPage.mPropEntries.TryGetValue(listViewItem, var propEntries);
if (propEntries == null)
return;
for (var propEntry in propEntries)
{
if (@propEntry == 0)
{
propEntry.mListViewItem.mParentItem.RemoveChildItem(propEntry.mListViewItem, false);
mDeferredDeleteList.Add(propEntry.mListViewItem);
}
propEntry.mListViewItem = null;
var typeOptions = (DistinctBuildOptions)propEntry.mTarget;
typeOptions.mCreateState = .Deleted;
}
}
protected void DeleteDistinctBuildOptions()
{
List<PropEntry> typeOptionsEntries = scope .();
for (var propEntryKV in mPropPage.mPropEntries)
{
var propEntry = propEntryKV.value[0];
if (propEntry.mPropertyName == "mFilter")
{
typeOptionsEntries.Add(propEntry);
}
}
for (var propEntry in typeOptionsEntries)
DeleteDistinctBuildOptions(propEntry.mListViewItem);
}
protected void UpdateDistinctBuildOptions(PropEntry propEntry)
{
if (propEntry.mListViewItem == null)
return;
var typeNames = propEntry.mCurValue.Get<String>();
var subItem = (DarkListViewItem)propEntry.mListViewItem.GetSubItem(1);
if ((typeNames.IsEmpty) || (typeNames == propEntry.mNotSetString))
{
subItem.Label = propEntry.mNotSetString;
subItem.mTextColor = 0xFFC0C0C0;
}
else
{
bool isValid = true;
for (let typeName in typeNames.Split(';'))
{
if ((!typeNames.StartsWith("@")) && (!gApp.mBfResolveCompiler.VerifyTypeName(scope String(typeName), -1)))
isValid = false;
}
subItem.mTextColor = isValid ? 0xFFFFFFFF : 0xFFFF8080;
propEntry.mColorOverride = subItem.mTextColor;
}
}
protected bool ApplyDistinctBuildOptions(List<DistinctBuildOptions> distinctBuildOptions, bool apply)
{
bool appliedChange = false;
for (let typeOptions in distinctBuildOptions)
{
if (typeOptions.mCreateState == .Normal)
continue;
if (((apply) && (typeOptions.mCreateState == .New)) ||
((!apply) && (typeOptions.mCreateState == .Deleted)))
{
typeOptions.mCreateState = .Normal;
continue;
}
if (apply)
appliedChange = true;
mDeferredDeleteList.Add(typeOptions);
@typeOptions.Remove();
}
return appliedChange;
}
protected void SetupDistinctBuildOptions(PropEntry propEntry)
{
propEntry.mNotSetString = "<Wildcard>";
UpdateDistinctBuildOptions(propEntry);
propEntry.mOnUpdate.Add(new () => { UpdateDistinctBuildOptions(propEntry); return true; });
propEntry.mIsTypeWildcard = true;
ImageWidget closeWidget = new ImageWidget();
closeWidget.mImage = DarkTheme.sDarkTheme.GetImage(.Close);
closeWidget.mOverImage = DarkTheme.sDarkTheme.GetImage(.CloseOver);
closeWidget.mOnMouseClick.Add(new (evt) =>
{
let valueItem = propEntry.mListViewItem.GetSubItem(1);
if (!valueItem.Label.IsEmpty)
{
let dialog = ThemeFactory.mDefault.CreateDialog("Remove?", "Are you sure you want to remove the selected custom build options?");
dialog.AddYesNoButtons(new (evt) =>
{
DeleteDistinctBuildOptions(propEntry.mListViewItem);
}, null, 0, 1);
dialog.PopupWindow(mWidgetWindow);
}
else
{
DeleteDistinctBuildOptions(propEntry.mListViewItem);
}
});
let subItem = propEntry.mListViewItem.GetSubItem(1);
subItem.AddWidget(closeWidget);
subItem.mOnResized.Add(new (evt) =>
{
let width = GetValueEditWidth(subItem);
closeWidget.Resize(width - GS!(21), GS!(-1), GS!(20), subItem.mHeight + 1);
});
}
}
}

View file

@ -0,0 +1,650 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.widgets;
using Beefy.theme;
using Beefy.gfx;
using Beefy.theme.dark;
using Beefy.events;
using Beefy.utils;
using IDE.Debugger;
using System.Diagnostics;
namespace IDE.ui
{
public class CallStackListViewItem : DarkVirtualListViewItem
{
public override void Draw(Graphics g)
{
base.Draw(g);
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
}
public ~this()
{
NOP!();
}
}
public class CallStackListView : DarkVirtualListView
{
CallStackPanel mCallStackPanel;
public bool mIconsDirty;
public this(CallStackPanel panel)
{
mCallStackPanel = panel;
}
protected override ListViewItem CreateListViewItem()
{
mIconsDirty = true;
return new CallStackListViewItem();
}
static void InsertColorChange(String str, int idx, uint32 color)
{
char8* insertChars = scope char8[5]*;
insertChars[0] = (char8)1;
*(uint32*)(insertChars + 1) = (color >> 1) & 0x7F7F7F7F;
str.Insert(idx, scope String(insertChars, 5));
}
public static void ColorizeLocationString(String label, int line = -1)
{
int prevStart = -1;
bool foundOpenParen = false;
// Check to see if this is just a Mixin name, don't mistake for the bang that separates module name
bool awaitingBang = label.Contains('!') && !label.EndsWith("!");
bool awaitingParamName = false;
int chevronCount = 0;
int parenCount = 0;
int lastTopStart = -1;
int lastTopEnd = -1;
for (int32 i = 0; i < label.Length; i++)
{
char8 c = label[i];
if ((c == '0') && (i == 0))
break; // Don't colorize addresses
if ((c == '<') && (i == 0))
{
uint32 color = 0xFFA0A0A0;//SourceEditWidgetContent.sTextColors[(int)SourceElementType.Comment];
InsertColorChange(label, 0, color);
label.Append('\x02');
break;
}
if (awaitingBang)
{
if ((c == ':') || (c == '<'))
{
awaitingBang = false;
i = -1;
continue;
}
if (c == '!')
{
bool endNow = false;
if (i + 1 < label.Length)
{
char16 nextC = label[i + 1];
if ((nextC == '(') || (nextC == '='))
{
awaitingBang = false;
i = -1;
continue;
}
else if ((nextC == '0') || (nextC == '<'))
{
endNow = true; // Just a raw string
}
}
uint32 color = 0xFFA0A0A0;//SourceEditWidgetContent.sTextColors[(int)SourceElementType.Comment];
InsertColorChange(label, 0, color);
awaitingBang = false;
i += 5;
label.Insert(i, '\x02');
if (endNow)
{
InsertColorChange(label, i + 2, SourceEditWidgetContent.sTextColors[(int32)SourceElementType.Method]);
break;
}
}
}
else if (c == '$')
{
uint32 color = 0xFF80A080;//SourceEditWidgetContent.sTextColors[(int)SourceElementType.Comment];
InsertColorChange(label, i, color);
i += 5;
}
else if ((c.IsLetterOrDigit) || (c == '_') || (c == '$') || (c == '@') /*|| (c == '>') || (c == '<') || (c == ':') || (c == '[') || (c == ']')*/)
{
if ((prevStart == -1) && (!awaitingParamName))
prevStart = i;
}
else
{
if (prevStart != -1)
{
//label.Insert(prevStart, SourceEditWidgetContent.sTextColors[(int)SourceElementType.TypeRef]);
uint32 color = SourceEditWidgetContent.sTextColors[(int32)SourceElementType.TypeRef];
/*if ((c == '+') || (c == '('))
{
foundOpenParen = true;
color = SourceEditWidgetContent.sTextColors[(int)SourceElementType.Method];
}*/
if (chevronCount == 0)
{
lastTopStart = prevStart;
lastTopEnd = i;
}
InsertColorChange(label, prevStart, color);
i += 5;
label.Insert(i, '\x02');
prevStart = -1;
awaitingParamName = false;
i++;
}
if (c == ',')
awaitingParamName = false;
if ((c == ')') && (parenCount > 0))
parenCount--;
if ((c == '(') && ((i == 0) || (chevronCount > 0)))
{
parenCount++;
}
else if ((c == '(') || (c == '+'))
{
foundOpenParen = true;
if (lastTopStart != -1)
{
char8* insertChars = label.CStr() + lastTopStart;
uint32 color = SourceEditWidgetContent.sTextColors[(int32)SourceElementType.Method];
*(uint32*)(insertChars + 1) = (color >> 1) & 0x7F7F7F7F;
}
else
{
int checkIdx = i - 1;
while (checkIdx > 0)
{
char8 checkC = label[checkIdx];
if (checkC == ':')
{
checkIdx++;
break;
}
checkIdx--;
}
if (checkIdx >= 0)
{
InsertColorChange(label, checkIdx, SourceEditWidgetContent.sTextColors[(int32)SourceElementType.Method]);
i += 5;
}
}
}
if ((foundOpenParen) && (!awaitingParamName) && (chevronCount == 0))
{
if (c == ' ')
{
bool nextIsName = true;
int32 spaceCount = 0;
for (int32 checkIdx = i + 1; checkIdx < label.Length; checkIdx++)
{
char8 checkC = label[checkIdx];
if (checkC == ' ')
{
spaceCount++;
if (spaceCount > 1)
nextIsName = false;
}
if ((checkC == '<') || (checkC == '*') || (checkC == '['))
nextIsName = false;
if ((checkC == ',') || (checkC == ')'))
{
if (spaceCount > 0)
nextIsName = false;
break;
}
}
if (nextIsName)
awaitingParamName = true;
}
}
}
if (c == '<')
chevronCount++;
else if (c == '>')
chevronCount--;
}
if (line != -1)
label.AppendF(" Line {0}", (int32)(line + 1));
}
public override void PopulateVirtualItem(DarkVirtualListViewItem listViewItem)
{
base.PopulateVirtualItem(listViewItem);
if (!gApp.mExecutionPaused)
return;
var callStackPanel = (CallStackPanel)listViewItem.mListView.mParent;
callStackPanel.SetStackFrame!();
listViewItem.mOnMouseDown.Add(new => mCallStackPanel.ValueClicked);
int addr;
String file = scope String();
int hotIdx;
int defLineStart;
int defLineEnd;
int line;
int column;
int language;
int stackSize;
String label = scope String(256);
DebugManager.FrameFlags frameFlags;
gApp.mDebugger.GetStackFrameInfo(listViewItem.mVirtualIdx, label, out addr, file, out hotIdx, out defLineStart, out defLineEnd, out line, out column, out language, out stackSize, out frameFlags);
ColorizeLocationString(label, line);
listViewItem.Label = label;
var subItem = listViewItem.CreateSubItem(1);
subItem.Label = ToStackString!((int32)stackSize);
subItem.mOnMouseDown.Add(new => mCallStackPanel.ValueClicked);
subItem = listViewItem.CreateSubItem(2);
if (language == 1)
{
if (frameFlags.HasFlag(DebugManager.FrameFlags.Optimized))
subItem.Label = "C++ (Optimized)";
else
subItem.Label = "C++";
}
else if (language == 2)
{
if (frameFlags.HasFlag(DebugManager.FrameFlags.Optimized))
subItem.Label = "Beef (Optimized)";
else
subItem.Label = "Beef";
}
subItem.mOnMouseDown.Add(new => mCallStackPanel.ValueClicked);
int32 callStackCount = gApp.mDebugger.GetCallStackCount();
DarkVirtualListViewItem headItem = (DarkVirtualListViewItem)GetRoot().GetMainItem();
headItem.mVirtualCount = callStackCount;
}
}
public class CallStackPanel : Panel
{
public CallStackListView mListView;
public bool mCallStackDirty = true;
public int32 mCallStackIdx;
public bool mDisabled;
public int32 mDisabledTicks;
public int32 mCallStackUpdateCnt;
public bool mWantsKeyboardFocus;
public int mThreadId = -1;
public int32 mActiveCallStackIdx = -1;
public int32 mSelectedCallStackIdx = -1;
public int32 ActiveCallStackIdx
{
get
{
if (mThreadId == -1)
return gApp.mDebugger.mActiveCallStackIdx;
return mActiveCallStackIdx;
}
set
{
if (mThreadId == -1)
gApp.mDebugger.mActiveCallStackIdx = value;
mActiveCallStackIdx = value;
}
}
public this()
{
mListView = new CallStackListView(this);
mListView.mShowGridLines = true;
mListView.InitScrollbars(true, true);
mListView.mHorzScrollbar.mPageSize = GS!(100);
mListView.mHorzScrollbar.mContentSize = GS!(500);
mListView.mVertScrollbar.mPageSize = GS!(100);
mListView.mVertScrollbar.mContentSize = GS!(500);
mListView.mOnLostFocus.Add(new (evt) => { mListView.GetRoot().SelectItemExclusively(null); });
mListView.mAutoFocus = true;
mListView.UpdateScrollbars();
AddWidget(mListView);
ListViewColumn column = mListView.AddColumn(GS!(400), "Location");
column.mMinWidth = GS!(100);
column = mListView.AddColumn(GS!(80), "Stack");
column = mListView.AddColumn(GS!(200), "Language");
SetScaleData();
//RebuildUI();
}
void SetScaleData()
{
mListView.mIconX = GS!(4);
mListView.mOpenButtonX = GS!(4);
mListView.mLabelX = GS!(26);
mListView.mChildIndent = GS!(16);
mListView.mHiliteOffset = GS!(-2);
}
public override void RehupScale(float oldScale, float newScale)
{
base.RehupScale(oldScale, newScale);
SetScaleData();
}
public override void Serialize(StructuredData data)
{
base.Serialize(data);
data.Add("Type", "CallStackPanel");
}
public override bool Deserialize(StructuredData data)
{
return base.Deserialize(data);
}
void UpdateIcons()
{
for (int32 callStackIdx = 0; callStackIdx < mListView.GetRoot().GetChildCount(); callStackIdx++)
{
var listViewItem = (DarkVirtualListViewItem)mListView.GetRoot().GetChildAtIndex(callStackIdx);
int32 virtIdx = listViewItem.mVirtualIdx;
int32 breakStackFrameIdx = gApp.mDebugger.GetBreakStackFrameIdx();
listViewItem.IconImage = null;
if ((virtIdx == breakStackFrameIdx) && (gApp.mDebugger.IsActiveThreadWaiting()))
{
listViewItem.IconImage = DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.RedDot);
}
if (virtIdx == 0)
{
if (virtIdx == ActiveCallStackIdx)
listViewItem.IconImage = DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.LinePointer);
}
else if (virtIdx == ActiveCallStackIdx)
listViewItem.IconImage = DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.LinePointer_Prev);
}
}
public void ValueClicked(MouseEvent theEvent)
{
SetStackFrame!();
DarkVirtualListViewItem clickedItem = (DarkVirtualListViewItem)theEvent.mSender;
DarkVirtualListViewItem item = (DarkVirtualListViewItem)clickedItem.GetSubItem(0);
mListView.SetFocus();
if (theEvent.mBtn == 1)
{
if (!item.Selected)
mListView.GetRoot().SelectItem(item, true);
}
else
{
mListView.GetRoot().SelectItem(item, true);
//mListView.GetRoot().SelectItemExclusively(item);
}
if ((theEvent.mBtn == 0) && (theEvent.mBtnCount > 1))
{
for (int32 childIdx = 1; childIdx < mListView.GetRoot().GetChildCount(); childIdx++)
{
var checkListViewItem = mListView.GetRoot().GetChildAtIndex(childIdx);
checkListViewItem.IconImage = null;
}
int32 selectedIdx = item.mVirtualIdx;
ActiveCallStackIdx = selectedIdx;
gApp.ShowPCLocation(selectedIdx, false, true);
gApp.StackPositionChanged();
}
UpdateIcons();
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
mListView.Resize(0, 0, width, height);
}
public void MarkCallStackDirty()
{
mCallStackDirty = true;
}
/*public override void LostFocus()
{
base.LostFocus();
mListView.GetRoot().SelectItemExclusively(null);
}*/
public override void FocusForKeyboard()
{
mListView.SetFocus();
mWantsKeyboardFocus = true;
}
public mixin SetStackFrame()
{
if (mThreadId != -1)
{
int prevActiveThread = gApp.mDebugger.GetActiveThread();
gApp.mDebugger.SetActiveThread((.)mThreadId);
defer:mixin gApp.mDebugger.SetActiveThread((.)prevActiveThread);
}
}
public void UpdateCallStack()
{
if ((!gApp.mExecutionPaused) || (!mCallStackDirty) || (mDisabled))
return;
int focusedIdx = -1;
HashSet<int> selectedIndices = scope .();
for (int itemIdx < (int)mListView.GetRoot().GetChildCount())
{
let lvItem = (CallStackListViewItem)mListView.GetRoot().GetChildAtIndex(itemIdx);
if (lvItem.Focused)
focusedIdx = lvItem.mVirtualIdx;
else if (lvItem.Selected)
selectedIndices.Add(lvItem.mVirtualIdx);
}
let prevScrollPos = mListView.mVertPos.v;
//Debug.WriteLine("CallStackPanel.Cleared {0}", gApp.mUpdateCnt);
mListView.VertScrollTo(0);
mListView.GetRoot().Clear();
gApp.mDebugger.CheckCallStack();
var listViewItem = (DarkVirtualListViewItem)mListView.GetRoot().CreateChildItem();
listViewItem.mVirtualHeadItem = listViewItem;
listViewItem.mVirtualCount = gApp.mDebugger.GetCallStackCount();
mListView.PopulateVirtualItem(listViewItem);
mCallStackUpdateCnt = 0;
mCallStackDirty = false;
UpdateIcons();
mListView.VertScrollTo(prevScrollPos);
mListView.UpdateAll();
for (int itemIdx < (int)mListView.GetRoot().GetChildCount())
{
let lvItem = (CallStackListViewItem)mListView.GetRoot().GetChildAtIndex(itemIdx);
if (lvItem.mVirtualIdx == focusedIdx)
lvItem.Focused = true;
else if (selectedIndices.Contains(lvItem.mVirtualIdx))
lvItem.Selected = true;
}
}
public override void Update()
{
base.Update();
SetStackFrame!();
if (!gApp.mDebugger.mIsRunning)
{
mListView.GetRoot().Clear();
}
else if ((gApp.mExecutionPaused) && (mCallStackDirty) && (!mDisabled))
{
UpdateCallStack();
}
else if (!mDisabled)
{
if ((mListView.GetRoot().GetChildCount() > 0) && (gApp.mIsUpdateBatchStart))
{
mCallStackUpdateCnt++;
var listViewItem = (DarkVirtualListViewItem)mListView.GetRoot().GetChildAtIndex(0);
gApp.mDebugger.CheckCallStack();
listViewItem.mVirtualCount = gApp.mDebugger.GetCallStackCount();
if (mCallStackUpdateCnt <= 2)
UpdateIcons();
}
}
else
{
mDisabledTicks++;
if ((mDisabledTicks > 40) && (!gApp.mDebuggerPerformingTask))
{
var root = mListView.GetRoot();
if (root.GetChildCount() != 0)
{
mListView.GetRoot().Clear();
MarkDirty();
}
}
}
if (mListView.mIconsDirty)
{
UpdateIcons();
mListView.mIconsDirty = false;
MarkDirty();
}
if (!mListView.mHasFocus)
mWantsKeyboardFocus = false;
if (mWantsKeyboardFocus)
{
int32 maxVirtIdx = 0;
int32 wantSelectIdx = gApp.mDebugger.mActiveCallStackIdx;
for (int32 i = 0; i < mListView.GetRoot().GetChildCount(); i++)
{
var listViewItem = (DarkVirtualListViewItem)mListView.GetRoot().GetChildAtIndex(i);
int32 virtIdx = listViewItem.mVirtualIdx;
if (virtIdx == wantSelectIdx)
{
mListView.GetRoot().SelectItem(listViewItem);
mListView.EnsureItemVisible(listViewItem, true);
mWantsKeyboardFocus = false;
}
maxVirtIdx = virtIdx;
}
/*if ((wantSelectIdx != -1) && (wantSelectIdx < mListView.GetRoot().GetChildCount()))
mListView.GetRoot().SelectItem(mListView.GetRoot().GetChildAtIndex(wantSelectIdx));*/
if (wantSelectIdx > maxVirtIdx)
{
mListView.VertScrollTo(mListView.mFont.GetLineSpacing() * maxVirtIdx);
}
}
}
bool TrySelectIdx(int idx)
{
for (int i < mListView.GetRoot().GetChildCount())
{
var listViewItem = (DarkVirtualListViewItem)mListView.GetRoot().GetChildAtIndex(i);
int32 virtIdx = listViewItem.mVirtualIdx;
if (virtIdx == idx)
{
mWantsKeyboardFocus = false;
mListView.GetRoot().SelectItemExclusively(listViewItem);
mListView.EnsureItemVisible(listViewItem, true);
return true;
}
}
return false;
}
public void SelectCallStackIdx(int idx)
{
UpdateCallStack();
if (TrySelectIdx(idx))
return;
float lineHeight = mListView.mFont.GetLineSpacing();
float approxScroll = lineHeight * (idx + 0.5f) - mListView.mScrollContentContainer.mHeight/2;
mListView.VertScrollTo(approxScroll);
mListView.UpdateAll();
TrySelectIdx(idx);
}
public void SetDisabled(bool disabled)
{
mDisabled = disabled;
mMouseVisible = !disabled;
mDisabledTicks = 0;
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
}
public override bool HasAffinity(Widget otherPanel)
{
return base.HasAffinity(otherPanel) || (otherPanel is ThreadPanel);
}
}
}

View file

@ -0,0 +1,992 @@
using Beefy.theme.dark;
using System;
using Beefy.widgets;
using Beefy.gfx;
using Beefy.events;
using Beefy.utils;
using System.Diagnostics;
using IDE.Compiler;
using System.Collections.Generic;
using System.Threading;
namespace IDE.ui
{
class ClassViewPanel : Panel
{
public class ClassViewListViewItem : IDEListViewItem
{
public float mLabelOffset;
public Object mRefObject;
public DataKind mKind;
public PendingEntry mMemberInfo ~ delete _;
protected override float GetLabelOffset()
{
return mLabelOffset;
}
public override float ResizeComponents(float xOffset)
{
return base.ResizeComponents(xOffset);
}
public override void DrawSelect(Graphics g)
{
bool hasFocus = mListView.mHasFocus;
if ((mWidgetWindow.mFocusWidget != null) && (mWidgetWindow.mFocusWidget.HasParent(mListView)))
hasFocus = true;
let parent = (ClassViewListView)mListView;
if (parent.mPanel.mFindClassDialog != null)
hasFocus = true;
using (g.PushColor(hasFocus ? 0xFFFFFFFF : 0x80FFFFFF))
base.DrawSelect(g);
}
public override void Draw(Graphics g)
{
base.Draw(g);
if (mRefObject != null)
{
bool hasChanged = false;
var workspace = mRefObject as Workspace;
if (workspace != null)
hasChanged = workspace.mHasChanged;
var project = mRefObject as Project;
if (project != null)
hasChanged = project.mHasChanged;
if (hasChanged)
g.DrawString("*", g.mFont.GetWidth(mLabel) + mLabelOffset + LabelX + 1, 0);
}
}
public void Init()
{
Image icon = null;
switch (mKind)
{
case .Project:
icon = DarkTheme.sDarkTheme.GetImage(.Project);
case .Namespace:
icon = DarkTheme.sDarkTheme.GetImage(.Namespace);
case .Class:
icon = DarkTheme.sDarkTheme.GetImage(.Type_Class);
case .Interface:
icon = DarkTheme.sDarkTheme.GetImage(.Interface);
case .ValueType:
icon = DarkTheme.sDarkTheme.GetImage(.Type_ValueType);
case .Field:
icon = DarkTheme.sDarkTheme.GetImage(.Field);
case .Property:
icon = DarkTheme.sDarkTheme.GetImage(.Property);
case .Method:
icon = DarkTheme.sDarkTheme.GetImage(.Method);
default:
}
IconImage = icon;
}
}
public class ClassViewListView : IDEListView
{
public ClassViewPanel mPanel;
protected override ListViewItem CreateListViewItem()
{
var anItem = new ClassViewListViewItem();
return anItem;
}
public override void KeyDown(KeyCode keyCode, bool isRepeat)
{
base.KeyDown(keyCode, isRepeat);
if (keyCode == .Return)
{
if (var item = (ClassViewListViewItem)GetRoot().FindFocusedItem())
mPanel.ShowItem(item);
}
else if (keyCode == .Tab)
{
if (this == mPanel.mTypeLV)
{
if (mWidgetWindow.IsKeyDown(.Shift))
mPanel.mSearchEdit.SetFocus();
else if (mPanel.mMemberLV != null)
{
if (mPanel.mMemberLV.GetRoot().GetChildCount() > 0)
{
if (mPanel.mMemberLV.GetRoot().FindFocusedItem() == null)
mPanel.mMemberLV.GetRoot().GetChildAtIndex(0).Focused = true;
mPanel.mMemberLV.SetFocus();
}
}
else
mPanel.mSearchEdit.SetFocus();
}
else
{
if (mWidgetWindow.IsKeyDown(.Shift))
mPanel.mTypeLV.SetFocus();
}
}
}
}
public class TypeArea : DockedWidget
{
public ClassViewPanel mPanel;
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
mPanel.mSearchEdit.Resize(GS!(2), GS!(4), width - GS!(4), GS!(24));
mPanel.mTypeLV.Resize(0, GS!(30), width, height - GS!(30));
}
public override void DrawAll(Beefy.gfx.Graphics g)
{
base.DrawAll(g);
using (g.PushColor(0x80FFFFFF))
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Bkg), 0, mHeight - GS!(1), mWidth, GS!(4));
}
}
public class PendingEntry : IHashable, IEquatable<PendingEntry>
{
public DataKind mKind;
public bool mShow = true;
public String mName ~ delete _;
public PendingEntry mParent;
public HashSet<PendingEntry> mChildren;
public List<PendingEntry> mSortedList;
public Object mRefObject;
public String mFile ~ delete _;
public int mLine;
public int mColumn;
public this()
{
}
public this(DataKind kind, String name)
{
mKind = kind;
mName = name;
}
public ~this()
{
if (mSortedList != null)
{
DeleteContainerAndItems!(mSortedList);
delete mChildren;
}
else
{
DeleteContainerAndItems!(mChildren);
}
}
void Detach()
{
mName = null;
}
public bool Equals(PendingEntry other)
{
return this == other;
}
public static bool operator==(PendingEntry val1, PendingEntry val2)
{
if (((Object)val1 == null) || ((Object)val2 == null))
return ((Object)val1 == null) && ((Object)val2 == null);
if ((val1.mKind != val2.mKind) && ((val1.mKind != .Namespace) && (val2.mKind != .Namespace)))
return false;
return (val1.mName == val2.mName);
}
public int GetHashCode()
{
return mName.GetHashCode();
}
public PendingEntry AddChild(DataKind kind, String name)
{
if (mChildren == null)
{
mChildren = new HashSet<PendingEntry>();
PendingEntry child = new PendingEntry(kind, new String(name));
if (mKind != .Root)
child.mParent = this;
Debug.Assert(child != (Object)this);
mChildren.Add(child);
return child;
}
PendingEntry pendingEntry = scope PendingEntry(kind, name);
PendingEntry* entryPtr;
if (mChildren.Add(pendingEntry, out entryPtr))
{
let child = new PendingEntry(kind, new String(name));
if (mKind != .Root)
child.mParent = this;
Debug.Assert(child != (Object)this);
*entryPtr = child;
}
else
{
if (kind > (*entryPtr).mKind)
(*entryPtr).mKind = kind;
}
pendingEntry.Detach();
return *entryPtr;
}
public void Sort()
{
if (mChildren == null)
return;
mSortedList = new List<PendingEntry>();
for (var entry in mChildren)
{
entry.Sort();
mSortedList.Add(entry);
}
mSortedList.Sort(scope (a, b) =>
{
DataKind lk = a.mKind;
DataKind rk = b.mKind;
if (lk < .Field)
lk = .ValueType;
if (rk < .Field)
rk = .ValueType;
int comp = lk <=> rk;
if (comp != 0)
return comp;
return a.mName.CompareTo(b.mName, true);
});
}
}
public enum DataKind
{
Root,
Project,
Globals,
Namespace,
Interface,
Class,
ValueType,
Field,
Property,
Method
}
class PendingInfo
{
public PendingEntry mPendingRoot ~ delete _;
public String mTypeStr ~ delete _;
public String mSearchStr ~ delete _;
public WaitEvent mDoneEvent = new .() ~ delete _;
}
public DarkDockingFrame mDockingFrame;
public DarkEditWidget mSearchEdit;
public ClassViewListView mTypeLV;
public ClassViewListView mMemberLV;
public int32 mLastCompileRevision;
public int32 mCompileRevisionDirtyDelay;
public bool mTypesDirty = true;
public bool mMembersDirty = true;
public int32 mWorkWait = -1;
public bool mWantsSubmit;
public String mRequestedTypeName = new .() ~ delete _;
public String mRequestedSearchStr = new .() ~ delete _;
PendingInfo mPendingInfo ~ delete _;
public List<PendingEntry> mHiddenEntries = new .() ~ DeleteContainerAndItems!(_);
public FindClassDialog mFindClassDialog;
public this(FindClassDialog findClassDialog = null)
{
mFindClassDialog = findClassDialog;
mSearchEdit = new DarkEditWidget();
mSearchEdit.mOnKeyDown.Add(new (evt) =>
{
if ((evt.mKeyCode == .Tab) && (evt.mKeyFlags == 0))
{
mTypeLV.SetFocus();
}
});
mTypeLV = new ClassViewListView();
mTypeLV.mPanel = this;
mTypeLV.SetShowHeader(false);
mTypeLV.InitScrollbars(true, true);
mTypeLV.mOnFocusChanged.Add(new => FocusChangedHandler);
mTypeLV.mOnItemMouseDown.Add(new => ItemMouseDown);
mTypeLV.mOnItemMouseClicked.Add(new => ListViewItemMouseClicked);
mTypeLV.mOnKeyDown.Add(new => ListViewKeyDown_ShowMenu);
if (mFindClassDialog == null)
{
mMemberLV = new ClassViewListView();
mMemberLV.mPanel = this;
mMemberLV.SetShowHeader(false);
mMemberLV.InitScrollbars(true, true);
mMemberLV.mOnItemMouseDown.Add(new => ItemMouseDown);
mMemberLV.mOnItemMouseClicked.Add(new => ListViewItemMouseClicked);
mMemberLV.mOnKeyDown.Add(new => ListViewKeyDown_ShowMenu);
var typeDock = new TypeArea();
typeDock.mPanel = this;
typeDock.AddWidget(mSearchEdit);
typeDock.AddWidget(mTypeLV);
var memberDock = new DockingProxy(mMemberLV);
mDockingFrame = new DarkDockingFrame();
mDockingFrame.mDrawBkg = false;
mDockingFrame.AddDockedWidget(typeDock, null, .Top);
mDockingFrame.AddDockedWidget(memberDock, typeDock, .Bottom);
AddWidget(mDockingFrame);
}
else
{
AddWidget(mTypeLV);
AddWidget(mSearchEdit);
mFindClassDialog.[Friend]mTabWidgets.Add(mTypeLV);
mFindClassDialog.[Friend]mTabWidgets.Add(mSearchEdit);
mSearchEdit.mOnKeyDown.Add(new => EditKeyDownHandler);
mSearchEdit.mOnSubmit.Add(new (evt) =>
{
mWantsSubmit = true;
});
}
//mListView.mDragEndHandler.Add(new => HandleDragEnd);
//mListView.mDragUpdateHandler.Add(new => HandleDragUpdate);
mTypeLV.mOnMouseDown.Add(new => ListViewMouseDown);
/*ListViewColumn column = mTypeLV.AddColumn(100, "Name");
column.mMinWidth = 40;*/
SetScaleData();
/*ListView lv = new MemberListView();
AddWidget(lv);
lv.Resize(100, 100, 300, 300);
let lvItem = lv.GetRoot().CreateChildItem();
lvItem.Label = "Yoofster";
lvItem.Focused = true;*/
}
public ~this()
{
if (mPendingInfo != null)
mPendingInfo.mDoneEvent.WaitFor();
}
void EditKeyDownHandler(KeyDownEvent evt)
{
switch (evt.mKeyCode)
{
case .Up,
.Down,
.Left,
.Right,
.PageUp,
.PageDown:
mTypeLV.KeyDown(evt.mKeyCode, false);
default:
}
if (evt.mKeyFlags == .Ctrl)
{
switch (evt.mKeyCode)
{
case .Home,
.End:
mTypeLV.KeyDown(evt.mKeyCode, false);
default:
}
}
}
void SetScaleData()
{
//mTypeLV.mColumns[0].mMinWidth = GS!(40);
mTypeLV.mIconX = GS!(20);
mTypeLV.mOpenButtonX = GS!(4);
mTypeLV.mLabelX = GS!(44);
mTypeLV.mChildIndent = GS!(16);
mTypeLV.mHiliteOffset = GS!(-2);
if (mMemberLV != null)
{
mMemberLV.mIconX = GS!(20);
mMemberLV.mOpenButtonX = GS!(4);
mMemberLV.mLabelX = GS!(44);
mMemberLV.mChildIndent = GS!(16);
mMemberLV.mHiliteOffset = GS!(-2);
}
}
public override void RehupScale(float oldScale, float newScale)
{
base.RehupScale(oldScale, newScale);
SetScaleData();
}
public override void FocusForKeyboard()
{
base.FocusForKeyboard();
mTypeLV.SetFocus();
}
public void StartRebuildUI()
{
Debug.Assert(mPendingInfo.mPendingRoot == null);
mPendingInfo.mPendingRoot = new .();
for (var project in IDEApp.sApp.mWorkspace.mProjects)
{
mPendingInfo.mPendingRoot.AddChild(.Project, project.mProjectName);
}
}
public override void Serialize(StructuredData data)
{
base.Serialize(data);
data.Add("Type", "ClassViewPanel");
}
public override bool Deserialize(StructuredData data)
{
return base.Deserialize(data);
}
void FocusChangedHandler(ListViewItem listViewItem)
{
if (listViewItem.Focused)
{
}
}
void ShowRightClickMenu(ProjectItem projectItem, float x, float y)
{
}
bool GetName(PendingEntry entry, String name)
{
if (entry.mParent != null)
{
if (GetName(entry.mParent, name))
name.Append(".");
}
if (entry.mKind == .Project)
{
name.Append(entry.mName);
name.Append(":");
return false;
}
name.Append(entry.mName);
return true;
}
bool GetName(ClassViewListViewItem item, String name)
{
if (item == null)
return false;
if (item.mMemberInfo != null)
return GetName(item.mMemberInfo, name);
if (item.mKind == .Project)
{
name.Append(item.mLabel);
name.Append(":");
return false;
}
let parentItem = (ClassViewListViewItem)item.mParentItem;
if (GetName(parentItem, name))
name.Append(".");
name.Append(item.mLabel);
return true;
}
void ShowItem(ClassViewListViewItem item)
{
void Show(String file, int line, int column)
{
gApp.RecordHistoryLocation(true);
gApp.ShowSourceFileLocation(file, -1, -1, line, column, .Always);
if (mFindClassDialog != null)
mFindClassDialog.Close();
}
if (item.mMemberInfo != null)
{
let info = item.mMemberInfo;
if (info.mFile != null)
{
Show(info.mFile, info.mLine, info.mColumn);
return;
}
}
String typeName = scope .();
GetName(item, typeName);
String info = scope .();
gApp.mBfResolveCompiler.GetTypeDefInfo(typeName, info);
for (let str in info.Split('\n'))
{
if (str.IsEmpty)
continue;
if (str[0] == 'S')
{
var srcInfo = str.Substring(1).Split('\t');
let filePath = srcInfo.GetNext().Get();
int lineNum = int.Parse(srcInfo.GetNext());
int column = int.Parse(srcInfo.GetNext());
Show(scope String()..Append(filePath), lineNum, column);
}
}
}
public void ItemMouseDown(ListViewItem item, float x, float y, int32 btnNum, int32 btnCount)
{
ListViewItemMouseDown(item, x, y, btnNum, btnCount);
let baseItem = (ClassViewListViewItem)item.GetSubItem(0);
if ((btnNum == 0) && (btnCount == 2))
{
ShowItem(baseItem);
}
}
void ListViewMouseDown(MouseEvent theEvent)
{
// We clicked off all items, so deselect
mTypeLV.GetRoot().WithSelectedItems(scope (item) => { item.Selected = false; } );
if (theEvent.mBtn == 1)
{
float aX, aY;
theEvent.GetRootCoords(out aX, out aY);
ShowRightClickMenu(null, aX, aY);
}
}
void ParseTypeInfo(String str)
{
List<PendingEntry> projectEntries = scope List<PendingEntry>();
PendingEntry curProject = null;
List<PendingEntry> partialRefs = scope List<PendingEntry>();
for (var subStrRef in str.Split('\n'))
{
String param = scope String();
param.Reference(subStrRef);
if (param.Length == 0)
continue;
char8 cmd = param[0];
param.AdjustPtr(1);
if (cmd == 'S')
continue;
int addIdx = -1;
PendingEntry parentEntry = null;
if (cmd == '>')
{
int atPos = param.IndexOf('@');
addIdx = int.Parse(StringView(param, 0, atPos)).Get();
param.AdjustPtr(atPos + 1);
cmd = param[0];
param.AdjustPtr(1);
}
else if (cmd == '<')
{
int atPos = param.IndexOf('@');
int refIdx = int.Parse(StringView(param, 0, atPos)).Get();
parentEntry = partialRefs[refIdx];
param.AdjustPtr(atPos + 1);
cmd = param[0];
param.AdjustPtr(1);
}
else if (cmd == ':')
{
parentEntry = mPendingInfo.mPendingRoot;
cmd = param[0];
param.AdjustPtr(1);
}
switch (cmd)
{
case '=':
int32 idx = int32.Parse(param);
curProject = projectEntries[idx];
case '+':
curProject = mPendingInfo.mPendingRoot.AddChild(.Project, param);
projectEntries.Add(curProject);
if (mPendingInfo.mSearchStr != null)
curProject.mShow = false;
case 'i', 'c', 'v', 'g':
var curEntry = curProject;
DataKind kind = .ValueType;
if (cmd == 'i')
kind = .Interface;
else if (cmd == 'c')
kind = .Class;
if (parentEntry != null)
{
if (parentEntry == (Object)mPendingInfo.mPendingRoot)
{
curEntry = parentEntry.AddChild(kind, param);
curEntry.mParent = curProject;
break;
}
if (parentEntry.mName == param)
{
parentEntry.mKind = kind;
break;
}
param.AdjustPtr(parentEntry.mName.Length + 1);
curEntry = parentEntry;
}
int nameIdx = 0;
for (var subName in param.Split('.'))
{
if (nameIdx < addIdx)
{
nameIdx++;
continue;
}
String subNameStr = scope String();
if (nameIdx == addIdx)
{
subNameStr.Reference(StringView(param, 0, @subName.MatchPos));
curEntry = mPendingInfo.mPendingRoot.AddChild(kind, subNameStr);
curEntry.mParent = curProject;
Debug.Assert(curProject != (Object)curEntry);
partialRefs.Add(curEntry);
nameIdx++;
addIdx = -1;
continue;
}
DataKind insertKind = kind;
bool isLast = subName.Ptr + subName.Length == param.Ptr + param.Length;
if (!isLast)
{
char8 nextChar = subName.Ptr[subName.Length];
if (nextChar == '.')
insertKind = .Namespace;
}
subNameStr.Reference(subName);
curEntry = curEntry.AddChild(insertKind, subNameStr);
nameIdx++;
}
default:
DataKind kind = default;
switch (cmd)
{
case 'I': kind = .Interface;
case 'C': kind = .Class;
case 'V': kind = .ValueType;
case 'F': kind = .Field;
case 'P': kind = .Property;
case 'M': kind = .Method;
}
var itr = param.Split('\t');
let entry = mPendingInfo.mPendingRoot.AddChild(kind, scope String()..Reference(itr.GetNext().Get()));
if (entry.mFile == null)
{
if (itr.GetNext() case .Ok(let fileName))
{
entry.mFile = new String(fileName);
entry.mLine = int.Parse(itr.GetNext()).Get();
entry.mColumn = int.Parse(itr.GetNext()).Get();
}
}
}
Debug.Assert(addIdx == -1);
}
mPendingInfo.mPendingRoot.Sort();
}
void BkgGetTypeList()
{
var bfSystem = gApp.mBfResolveSystem;
var bfCompiler = gApp.mBfResolveCompiler;
bfSystem.Lock(0);
String outStr = scope String();
if (mPendingInfo.mSearchStr != null)
bfCompiler.GetTypeDefMatches(mPendingInfo.mSearchStr, outStr);
else
bfCompiler.GetTypeDefList(outStr);
bfSystem.Unlock();
ParseTypeInfo(outStr);
mPendingInfo.mDoneEvent.Set();
}
void BkgGetTypeInfo()
{
var bfSystem = gApp.mBfResolveSystem;
var bfCompiler = gApp.mBfResolveCompiler;
bfSystem.Lock(0);
String info = scope .();
bfCompiler.GetTypeDefInfo(mPendingInfo.mTypeStr, info);
bfSystem.Unlock();
ParseTypeInfo(info);
mPendingInfo.mDoneEvent.Set();
}
void HandleEntries(ClassViewListViewItem listViewItem, PendingEntry pendingEntry)
{
int32 curIdx = 0;
if (pendingEntry.mSortedList != null)
{
for (var child in pendingEntry.mSortedList)
{
if (!child.mShow)
{
@child.Current = null;
mHiddenEntries.Add(child);
continue;
}
ClassViewListViewItem childListViewItem;
if (curIdx < listViewItem.GetChildCount())
{
childListViewItem = (ClassViewListViewItem)listViewItem.GetChildAtIndex(curIdx);
}
else
{
childListViewItem = (ClassViewListViewItem)listViewItem.CreateChildItem();
}
childListViewItem.Label = child.mName;
childListViewItem.mRefObject = pendingEntry.mRefObject;
childListViewItem.mOpenOnDoubleClick = false;
childListViewItem.mKind = child.mKind;
DeleteAndNullify!(childListViewItem.mMemberInfo);
//if (child.mFile != null)
{
childListViewItem.mMemberInfo = child;
@child.Current = null;
}
childListViewItem.Init();
HandleEntries(childListViewItem, child);
curIdx++;
}
}
while (curIdx < listViewItem.GetChildCount())
listViewItem.RemoveChildItemAt(curIdx);
listViewItem.TryUnmakeParent();
}
public override void Update()
{
base.Update();
var focusedItem = (ClassViewListViewItem)mTypeLV.GetRoot().FindFocusedItem();
var focusedStr = scope String();
if (focusedItem != null)
GetName(focusedItem, focusedStr);
int32 compileRevision = gApp.mBfResolveCompiler.GetCompileRevision();
if (mLastCompileRevision != compileRevision)
{
mCompileRevisionDirtyDelay = 30;
mLastCompileRevision = compileRevision;
}
if ((mCompileRevisionDirtyDelay > 0) && (--mCompileRevisionDirtyDelay == 0))
{
mTypesDirty = true;
mMembersDirty = true;
}
var searchStr = scope String();
mSearchEdit.GetText(searchStr);
searchStr.Trim();
if (mPendingInfo != null)
{
mWorkWait++;
if (gApp.mUpdateCnt % 10 == 0)
MarkDirty();
if (mPendingInfo.mDoneEvent.WaitFor(0))
{
if (mPendingInfo.mTypeStr != null)
{
if (mPendingInfo.mTypeStr == focusedStr)
HandleEntries((ClassViewListViewItem)mMemberLV.GetRoot(), mPendingInfo.mPendingRoot);
}
else if (mPendingInfo.mPendingRoot != null)
{
ClearAndDeleteItems(mHiddenEntries);
HandleEntries((ClassViewListViewItem)mTypeLV.GetRoot(), mPendingInfo.mPendingRoot);
focusedItem = (ClassViewListViewItem)mTypeLV.GetRoot().FindFocusedItem();
if ((focusedItem == null) && (mTypeLV.GetRoot().GetChildCount() != 0))
{
mTypeLV.GetRoot().GetChildAtIndex(0).Focused = true;
}
}
DeleteAndNullify!(mPendingInfo);
mWorkWait = -1;
MarkDirty();
}
}
if (mPendingInfo == null)
{
bool TryStartWork()
{
mWorkWait++;
return !gApp.mBfResolveCompiler.IsPerformingBackgroundOperation();
}
if (!searchStr.IsEmpty)
{
bool hasFocus = mHasFocus;
if ((mWidgetWindow.mFocusWidget != null) && (mWidgetWindow.mFocusWidget.HasParent(this)))
hasFocus = true;
if ((searchStr != mRequestedSearchStr) ||
((mTypesDirty) && (hasFocus)))
{
if (TryStartWork())
{
mPendingInfo = new .();
mPendingInfo.mPendingRoot = new .();
mPendingInfo.mSearchStr = new String(searchStr);
gApp.mBfResolveCompiler.DoBackground(new => BkgGetTypeList);
mRequestedSearchStr.Set(searchStr);
mTypesDirty = false;
}
}
}
else
{
if ((searchStr != mRequestedSearchStr) || (mTypesDirty))
{
if (TryStartWork())
{
mPendingInfo = new .();
StartRebuildUI();
//Debug.WriteLine("Rebuilding UI...");
gApp.mBfResolveCompiler.DoBackground(new => BkgGetTypeList);
mRequestedSearchStr.Set(searchStr);
mTypesDirty = false;
}
}
}
if ((mPendingInfo == null) && (mMemberLV != null))
{
if ((mRequestedTypeName != focusedStr) || (mMembersDirty))
{
if (TryStartWork())
{
mPendingInfo = new PendingInfo();
mPendingInfo.mTypeStr = new String(focusedStr);
mPendingInfo.mPendingRoot = new .();
gApp.mBfResolveCompiler.DoBackground(new => BkgGetTypeInfo);
mRequestedTypeName.Set(focusedStr);
mMembersDirty = false;
}
}
}
}
if (mWorkWait == -1)
{
if (mWantsSubmit)
mTypeLV.KeyDown(.Return, false);
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
if (mDockingFrame != null)
mDockingFrame.Resize(0, 0, mWidth, mHeight);
else
{
float insetSize = GS!(6);
mTypeLV.Resize(GS!(6), GS!(6), mWidth - GS!(12), mHeight - GS!(32));
mSearchEdit.Resize(insetSize, mTypeLV.mY + mTypeLV.mHeight + insetSize, mWidth - insetSize - insetSize, GS!(22));
}
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
void DrawRefresh(Widget widget, int life)
{
widget.SelfToOtherTranslate(this, 0, 0, var x, var y);
using (g.PushColor(0x60505050))
g.FillRect(x, y, widget.Width, widget.Height);
IDEUtils.DrawWait(g, x + widget.Width/2, y + widget.Height/2, life);
}
if (mWorkWait >= 30)
{
bool hasFocus = mHasFocus;
if ((mWidgetWindow.mFocusWidget != null) && (mWidgetWindow.mFocusWidget.HasParent(this)))
hasFocus = true;
bool hasContent = (mTypeLV.GetRoot().GetChildCount() > 0) || (!mSearchEdit.IsWhiteSpace());
if ((hasFocus) || (!hasContent))
{
if (mPendingInfo?.mTypeStr != null)
DrawRefresh(mMemberLV, mUpdateCnt);
else
DrawRefresh(mTypeLV, mUpdateCnt);
}
}
if (mFindClassDialog != null)
IDEUtils.DrawOutline(g, mTypeLV);
}
}
}

View file

@ -0,0 +1,382 @@
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);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Beefy.theme.dark;
using System.Diagnostics;
namespace IDE.ui
{
public class FileChangedDialog : DarkDialog
{
public enum DialogKind
{
Changed,
Deleted,
COUNT
}
List<String> mFileNames = new List<String>() ~ DeleteContainerAndItems!(_);
public bool?[(int)DialogKind.COUNT] mApplyAllResult;
public DialogKind mDialogKind;
public this()
{
}
public ~this()
{
Debug.Assert(gApp.mFileChangedDialog != this);
gApp.mFileChangedDialog = null;
}
public void Show(SourceViewPanel sourceViewPanel)
{
String fileName = sourceViewPanel.mFilePath;
bool exists = File.Exists(fileName);
mFileNames.Add(new String(fileName));
if ((sourceViewPanel.mProjectSource != null) && (sourceViewPanel.mProjectSource.mEditData != null))
{
var editData = sourceViewPanel.mProjectSource.mEditData;
editData.mFileDeleted = !exists;
}
if (exists)
{
mDialogKind = .Changed;
if (mFileNames.Count == 1)
Title = "File Changed";
else
Title = "Files Changed";
mText = new String();
mText.AppendF("{0}\n\nThe file has unsaved changes inside this editor and has been changed externally.\nDo you want to reload it and lose the changes made in the source editor?", fileName);
if (!mInPopupWindow)
{
AddYesNoButtons(new (evt) =>
{
sourceViewPanel.Reload();
}, new (evt) =>
{
sourceViewPanel.RefusedReload();
});
}
}
else
{
mDialogKind = .Deleted;
if (mFileNames.Count == 1)
Title = "File Deleted";
else
Title = "Files Deleted";
/*if (sourceViewPanel.mEditData != null)
{
sourceViewPanel.mEditData.mLastFileTextVersion = -1;
}*/
//sourceViewPanel.mEditData.mWasDeleted = true;
mText = new String();
mText.AppendF("{0}\n\nThe file is open in this editor and has been deleted externally.\nDo you want to close this file?", fileName);
if (!mInPopupWindow)
{
AddYesNoButtons(new (evt) =>
{
gApp.CloseDocument(sourceViewPanel);
});
}
}
var button = AddButton("Yes To All");
button.mOnMouseClick.Add(new (evt) =>
{
if (mDialogKind == .Deleted)
gApp.CloseDocument(sourceViewPanel);
else
sourceViewPanel.Reload();
mApplyAllResult[(int)mDialogKind] = true;
});
button = AddButton("No To All");
button.mOnMouseClick.Add(new (evt) =>
{
if (mDialogKind == .Deleted)
{
// Nothing
}
else
sourceViewPanel.RefusedReload();
mApplyAllResult[(int)mDialogKind] = false;
});
PopupWindow(IDEApp.sApp.mMainWindow);
}
public void Rehup()
{
base.Update();
if (mDialogKind == .Deleted)
{
bool allFilesExist = true;
for (var fileName in mFileNames)
{
allFilesExist &= File.Exists(fileName);
}
if (allFilesExist)
Close();
}
}
}
}

View file

@ -0,0 +1,305 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.gfx;
using Beefy.theme.dark;
using Beefy.widgets;
namespace IDE.ui
{
public class FindAndReplaceDialog : IDEDialog
{
EditWidget mEditWidget;
EditWidget mReplaceWidget;
DarkComboBox mLocationCombo;
DarkComboBox mFileTypesCombo;
bool mIsReplace;
DarkCheckBox mRecurseDirCheckbox;
DarkCheckBox mMatchCaseCheckbox;
DarkCheckBox mMatchWholeWordCheckbox;
bool mIgnoreContentChanged;
DarkButton mAbortButton;
public this(bool isReplace)
{
mSettingHistoryManager = gApp.mFindAndReplaceHistoryManager;
mIsReplace = isReplace;
mWindowFlags = BFWindow.Flags.ClientSized | BFWindow.Flags.TopMost | BFWindow.Flags.Caption |
BFWindow.Flags.Border | BFWindow.Flags.SysMenu | BFWindow.Flags.Resizable;
AddOkCancelButtons(new (evt) => { DoFind(); }, null, 0, 1);
mButtonBottomMargin = GS!(6);
mButtonRightMargin = GS!(6);
mEditWidget = AddEdit("");
if (mIsReplace)
{
mReplaceWidget = AddEdit("");
}
mLocationCombo = new PathComboBox();
mLocationCombo.MakeEditable(new PathEditWidget());
mLocationCombo.Label = FindResultsPanel.sEntireSolution;
mLocationCombo.mPopulateMenuAction.Add(new => PopulateLocationMenu);
mLocationCombo.mEditWidget.mOnContentChanged.Add(new (evt) => { UpdateUI(); });
AddWidget(mLocationCombo);
AddEdit(mLocationCombo.mEditWidget);
mFileTypesCombo = new DarkComboBox();
mFileTypesCombo.MakeEditable();
mFileTypesCombo.Label = "*";
mFileTypesCombo.mPopulateMenuAction.Add(new => PopulateFileTypesMenu);
AddWidget(mFileTypesCombo);
AddEdit(mFileTypesCombo.mEditWidget);
mRecurseDirCheckbox = new DarkCheckBox();
mRecurseDirCheckbox.Label = "&Recurse directories";
mRecurseDirCheckbox.Checked = true;
AddDialogComponent(mRecurseDirCheckbox);
mMatchCaseCheckbox = new DarkCheckBox();
mMatchCaseCheckbox.Label = "Match &case";
AddDialogComponent(mMatchCaseCheckbox);
mMatchWholeWordCheckbox = new DarkCheckBox();
mMatchWholeWordCheckbox.Label = "Match &whole case";
AddDialogComponent(mMatchWholeWordCheckbox);
mAbortButton = new DarkButton();
mAbortButton.Label = "Abort Current";
mAbortButton.mOnMouseClick.Add(new (evt) =>
{
gApp.mFindResultsPanel.CancelSearch();
});
AddDialogComponent(mAbortButton);
mAbortButton.mVisible = false;
CreatePrevNextButtons();
UpdateUI();
//mEditWidget.mKeyDownHandler += EditKeyDownHandler;
//mEditWidget.mContentChangedHandler += (evt) => mFilterChanged = true;
}
protected override void UseProps(PropertyBag propBag)
{
mIgnoreContentChanged = true;
mEditWidget.SetText(propBag.Get<String>("Find") ?? "");
mEditWidget.mEditWidgetContent.SelectAll();
if (mReplaceWidget != null)
mReplaceWidget.SetText(propBag.Get<String>("Replace") ?? "");
mLocationCombo.Label = propBag.Get<String>("Location", FindResultsPanel.sEntireSolution) ?? "";
mFileTypesCombo.Label = propBag.Get<String>("FileTypes", "*") ?? "";
mRecurseDirCheckbox.Checked = propBag.Get<bool>("RecurseDir", true);
mMatchCaseCheckbox.Checked = propBag.Get<bool>("MatchCase");
mMatchWholeWordCheckbox.Checked = propBag.Get<bool>("MatchWholeWord");
mIgnoreContentChanged = false;
UpdateUI();
}
void SaveProps()
{
PropertyBag propBag = new PropertyBag();
var str = scope String();
mEditWidget.GetText(str);
propBag.Add("Find", str);
if (mReplaceWidget != null)
{
str.Clear();
mReplaceWidget.GetText(str);
propBag.Add("Replace", str);
}
propBag.Add("Location", mLocationCombo.Label);
propBag.Add("FileTypes", mFileTypesCombo.Label);
propBag.Add("RecurseDir", mRecurseDirCheckbox.Checked);
propBag.Add("MatchCase", mMatchCaseCheckbox.Checked);
propBag.Add("MatchWholeWord", mMatchWholeWordCheckbox.Checked);
mSettingHistoryManager.Add(propBag);
}
void UpdateUI()
{
if (mIgnoreContentChanged)
return;
bool foundLocation = false;
for (var str in FindResultsPanel.sLocationStrings)
{
if (str == mLocationCombo.Label)
{
foundLocation = true;
break;
}
}
mRecurseDirCheckbox.mDisabled = foundLocation;
UpdateProgress();
}
void UpdateProgress()
{
var title = scope String();
title.Append(mIsReplace ? "Find and Replace in Files" : "Find in Files");
bool isSearching = gApp.mFindResultsPanel.IsSearching;
if (mAbortButton.mVisible != isSearching)
{
mAbortButton.mVisible = isSearching;
mDefaultButton.mDisabled = isSearching;
MarkDirty();
if (!isSearching)
Title = title;
}
if ((isSearching) && (mUpdateCnt % 8 == 0))
{
title.Append(" - Searching");
title.Append('.', (mUpdateCnt / 30) % 4);
MarkDirty();
}
Title = title;
}
void PopulateLocationMenu(Menu menu)
{
for (var str in FindResultsPanel.sLocationStrings)
{
var item = menu.AddItem(str);
item.mOnMenuItemSelected.Add(new (dlg) =>
{
mIgnoreContentChanged = true;
mLocationCombo.Label = str;
mIgnoreContentChanged = false;
});
}
}
void PopulateFileTypesMenu(Menu menu)
{
var strings = scope List<String>();
strings.Add("*");
strings.Add("*.bf");
for (var str in strings)
{
var item = menu.AddItem(str);
item.mOnMenuItemSelected.Add(new (dlg) => { mFileTypesCombo.Label = str; });
}
}
void DoFind()
{
IDEApp.sApp.ShowFindResults(false);
FindResultsPanel.SearchOptions searchOptions = new FindResultsPanel.SearchOptions();
searchOptions.mSearchString = new String();
mEditWidget.GetText(searchOptions.mSearchString);
if (mReplaceWidget != null)
{
searchOptions.mReplaceString = new String();
mReplaceWidget.GetText(searchOptions.mReplaceString);
}
searchOptions.mSearchLocation = new String(mLocationCombo.Label);
searchOptions.mFileTypes = new List<String>();
var fileTypes = scope String();
mFileTypesCombo.GetLabel(fileTypes);
for (var fileType in fileTypes.Split(';'))
searchOptions.mFileTypes.Add(new String(fileType));
searchOptions.mRecurseDirectories = mRecurseDirCheckbox.Checked;
searchOptions.mMatchCase = mMatchCaseCheckbox.Checked;
searchOptions.mMatchWholeWord = mMatchWholeWordCheckbox.Checked;
gApp.mFindResultsPanel.Search(searchOptions);
SaveProps();
}
public override void ResizeComponents()
{
base.ResizeComponents();
float curY = GS!(30);
mAbortButton.Resize(GS!(6), mDefaultButton.mY, mFont.GetWidth(mAbortButton.mLabel) + GS!(30), mDefaultButton.mHeight);
mEditWidget.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
if (mReplaceWidget != null)
{
curY += GS!(42);
mReplaceWidget.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
}
curY += GS!(42);
mLocationCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
curY += GS!(42);
mFileTypesCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
curY += GS!(28);
mRecurseDirCheckbox.Resize(GS!(6), curY, mRecurseDirCheckbox.CalcWidth(), GS!(22));
curY += GS!(22);
mMatchCaseCheckbox.Resize(GS!(6), curY, mMatchCaseCheckbox.CalcWidth(), GS!(22));
curY += GS!(22);
mMatchWholeWordCheckbox.Resize(GS!(6), curY, mMatchWholeWordCheckbox.CalcWidth(), GS!(22));
}
public override void CalcSize()
{
mWidth = GS!(400);
mHeight = GS!(mIsReplace ? 280 : 240);
}
public override void AddedToParent()
{
base.AddedToParent();
RehupMinSize();
}
void RehupMinSize()
{
mWidgetWindow.SetMinimumSize(GS!(300), (.)GS!(mIsReplace ? 264 : 224), true);
}
public override void RehupScale(float oldScale, float newScale)
{
base.RehupScale(oldScale, newScale);
RehupMinSize();
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
public override void Draw(Graphics g)
{
base.Draw(g);
g.DrawString("Find what:", 6, mEditWidget.mY - GS!(18));
if (mReplaceWidget != null)
g.DrawString("Replace with:", GS!(6), mReplaceWidget.mY - GS!(18));
g.DrawString("Look in:", GS!(6), mLocationCombo.mY - GS!(18));
g.DrawString("Look at these file types:", GS!(6), mFileTypesCombo.mY - GS!(18));
}
public override void Update()
{
base.Update();
UpdateProgress();
}
}
}

View file

@ -0,0 +1,49 @@
using Beefy.theme.dark;
using Beefy.widgets;
using System;
namespace IDE.ui
{
class FindClassDialog : IDEDialog
{
ClassViewPanel mClassViewPanel;
public this()
{
mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable;
AddOkCancelButtons(new (evt) => { GotoClass(); }, null, 0, 1);
Title = "Find Class";
mButtonBottomMargin = GS!(6);
mButtonRightMargin = GS!(6);
mClassViewPanel = new ClassViewPanel(this);
AddWidget(mClassViewPanel);
}
public override void CalcSize()
{
mWidth = GS!(660);
mHeight = GS!(512);
}
void GotoClass()
{
mClassViewPanel.[Friend]mSearchEdit.mOnSubmit(null);
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
mClassViewPanel.Resize(0, 0, width, height - GS!(34));
}
public override void PopupWindow(WidgetWindow parentWindow, float offsetX, float offsetY)
{
base.PopupWindow(parentWindow, offsetX, offsetY);
mClassViewPanel.[Friend]mSearchEdit.SetFocus();
}
}
}

View file

@ -0,0 +1,731 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy.widgets;
using Beefy.utils;
using Beefy.theme.dark;
using System.Threading;
using Beefy;
using System.IO;
using System.Diagnostics;
using IDE.Util;
namespace IDE.ui
{
public class FindResultsPanel : OutputPanel
{
public static String sCurrentDocument = "Current Document";
public static String sCurrentProject = "Current Project";
public static String sEntireSolution = "Entire Solution";
public static String[] sLocationStrings = new .(sCurrentDocument, sCurrentProject, sEntireSolution) ~ delete _;
List<String> mPendingLines = new List<String>() ~ DeleteContainerAndItems!(_);
int32 mCurLineNum;
HashSet<String> mFoundPathSet ~ DeleteContainerAndItems!(_);
List<String> mSearchPaths ~ DeleteContainerAndItems!(_);
SearchOptions mSearchOptions ~ delete _;
Thread mSearchThread ~ delete _;
Monitor mMonitor = new Monitor() ~ delete _;
bool mCancelling;
//bool mAbortSearch;
public class SearchOptions
{
public String mSearchString ~ delete _;
public String mReplaceString ~ delete _;
public String mSearchLocation ~ delete _;
public List<String> mFileTypes ~ DeleteContainerAndItems!(_);
public bool mMatchCase;
public bool mMatchWholeWord;
public bool mRecurseDirectories;
public bool mDeferredFindFiles;
}
// This is so we can remap to the correct source location even if we add or remove lines above the found line
class LineSrcInfo
{
public FileEditData mEditData;
public int32 mCharId;
public int32 mLine;
public int32 mLineChar;
}
List<LineSrcInfo> mLineSrcInfo = new List<LineSrcInfo>() ~ DeleteContainerAndItems!(_);
bool mHasUnboundLineSrcInfos;
int32 mLastEditDataRevision;
class FindInfo
{
public String mContent ~ delete _;
}
Dictionary<String, FindInfo> mFindInfoMap = new Dictionary<String, FindInfo>() ~ { for (var kv in mFindInfoMap) delete kv.value; delete _; };
List<String> mDeferredReplacePaths = new List<String>() ~ DeleteContainerAndItems!(_);
public this()
{
((OutputWidgetContent)mOutputWidget.mEditWidgetContent).mGotoReferenceEvent.Add(new => GotoRefrenceAtLine);
}
bool GotoRefrenceAtLine(int line, int lineOfs)
{
if (line >= mLineSrcInfo.Count)
return false;
var lineSrcInfo = ref mLineSrcInfo[line];
if (lineSrcInfo == null)
return false;
if (lineSrcInfo.mEditData.mEditWidget == null)
return false;
var editWidgetContent = lineSrcInfo.mEditData.mEditWidget.mEditWidgetContent;
if (editWidgetContent == null)
return false;
int charIdx = editWidgetContent.mData.mTextIdData.GetPrepared().GetIndexFromId(lineSrcInfo.mCharId);
if (charIdx == -1)
return false;
int remappedLine;
int remappedLineChar;
editWidgetContent.GetLineCharAtIdx(charIdx, out remappedLine, out remappedLineChar);
var filePath = lineSrcInfo.mEditData.mFilePath;
IDEApp.sApp.ShowSourceFileLocation(filePath, -1, -1/*IDEApp.sApp.mWorkspace.GetHighestCompileIdx()*/, remappedLine, remappedLineChar, LocatorType.Always);
return true;
}
bool IsWordChar(char32 c32)
{
return c32.IsLetterOrDigit || (c32 == '_');
}
void SearchThread()
{
int32 linesMatched = 0;
int32 filesMatched = 0;
int32 filesSearched = 0;
if (mSearchOptions.mDeferredFindFiles)
{
AddFilesFromDirectory(mSearchOptions.mSearchLocation, mSearchOptions);
}
String line = scope String();
for (var filePath in mSearchPaths)
FileBlock:
{
filesSearched++;
if (mCancelling)
break;
StreamReader reader = null;
String fileText = null;
if (mSearchOptions.mSearchString.IsEmpty)
break;
FindInfo findInfo;
if (mFindInfoMap.TryGetValue(filePath, out findInfo))
{
fileText = findInfo.mContent;
}
if (fileText != null)
{
let strStream = scope:FileBlock StringStream(fileText, .Reference);
reader = scope:FileBlock StreamReader(strStream, UTF8Encoding.UTF8, false, 1024);
}
else
{
let streamReader = new StreamReader();
if (streamReader.Open(filePath) case .Err(let errCode))
{
delete streamReader;
if (errCode != .NotFound)
QueueLine(scope String()..AppendF("Failed to open file: {0}", filePath));
continue;
}
reader = streamReader;
defer:FileBlock delete reader;
}
bool hasDeferredReplace = false;
if (reader != null)
{
char8* searchPtr = mSearchOptions.mSearchString.Ptr;
int searchLength = mSearchOptions.mSearchString.Length;
bool hadMatch = false;
int32 lineNum = 0;
while (!reader.EndOfStream)
{
if (mCancelling)
break;
line.Clear();
reader.ReadLine(line);
char8* linePtr = line.Ptr;
bool lineMatched;
if (mSearchOptions.mMatchWholeWord)
{
bool isNewStart = true;
int lineIdx = 0;
for (let c32 in line.DecodedChars)
{
if ((isNewStart) && (mSearchOptions.mMatchCase ?
String.EqualsHelper(linePtr + lineIdx, searchPtr, searchLength) :
String.EqualsIgnoreCaseHelper(linePtr + lineIdx, searchPtr, searchLength)))
{
int checkIdx = lineIdx + searchLength;
if (checkIdx >= line.Length)
{
lineMatched = true;
break;
}
char32 nextC = line.GetChar32(checkIdx).c;
if (!IsWordChar(nextC))
{
lineMatched = true;
break;
}
}
isNewStart = !IsWordChar(c32);
lineIdx = @c32.NextIndex;
}
}
else
lineMatched = line.IndexOf(mSearchOptions.mSearchString, !mSearchOptions.mMatchCase) != -1;
if (lineMatched)
{
linesMatched++;
hadMatch = true;
if (mSearchOptions.mReplaceString != null)
{
hasDeferredReplace = true;
break;
}
else
{
const int maxLen = 4096;
if (line.Length >= maxLen)
{
line.RemoveToEnd(maxLen);
line.Append("...");
}
for (var c in ref line.RawChars)
{
if (c.IsControl)
c = ' ';
}
QueueLine(filePath, lineNum, 0, line);
}
}
lineNum++;
}
if (hadMatch)
filesMatched++;
}
if (hasDeferredReplace)
{
mDeferredReplacePaths.Add(filePath);
}
}
String outLine = scope String();
if (mSearchOptions.mReplaceString != null)
outLine.AppendF("Replacing text in {0} file{1}. Total files searched: {2}", filesMatched, (filesMatched == 1) ? "" : "s", filesSearched);
else
outLine.AppendF("Matching lines: {0} Matching files: {1} Total files searched: {2}", linesMatched, filesMatched, filesSearched);
QueueLine(outLine);
if (mCancelling)
QueueLine("Search cancelled");
}
public bool IsSearching
{
get
{
return mSearchThread != null;
}
}
public void CancelSearch()
{
mCancelling = true;
}
void StopSearch()
{
if (mSearchThread != null)
{
mSearchThread.Join();
DeleteAndNullify!(mSearchThread);
DeleteAndNullify!(mSearchOptions);
ClearAndDeleteItems(mPendingLines);
DeleteContainerAndItems!(mSearchPaths);
mSearchPaths = null;
DeleteContainerAndItems!(mFoundPathSet);
mFoundPathSet = null;
for (var kv in mFindInfoMap)
delete kv.value;
mFindInfoMap.Clear();
mDeferredReplacePaths.Clear();
mCancelling = false;
}
}
bool PassesFilter(StringView fileName, SearchOptions searchOptions)
{
bool passes = false;
if (searchOptions.mFileTypes.IsEmpty)
passes = true;
for (let fileType in searchOptions.mFileTypes)
{
if (fileType == "*")
{
passes = true;
continue;
}
if (Path.WildcareCompare(fileName, fileType))
{
passes = true;
break;
}
}
return passes;
}
void AddFromFilesFolder(ProjectFolder projectFolder, SearchOptions searchOptions)
{
for (var projectEntry in projectFolder.mChildItems)
{
var childFolder = projectEntry as ProjectFolder;
if (childFolder != null)
AddFromFilesFolder(childFolder, searchOptions);
var projectSource = projectEntry as ProjectSource;
if (projectSource != null)
{
var path = scope String();
projectSource.GetFullImportPath(path);
var upperPath = scope String(path);
IDEUtils.FixFilePath(upperPath);
if (!Environment.IsFileSystemCaseSensitive)
upperPath.ToUpper();
if ((!mFoundPathSet.Contains(upperPath)) && (PassesFilter(path, searchOptions)))
{
mSearchPaths.Add(new String(path));
mFoundPathSet.Add(new String(upperPath));
}
}
}
}
void AddFilesFromDirectory(StringView dirPath, SearchOptions searchOptions)
{
if (mCancelling)
return;
for (var fileEntry in Directory.EnumerateFiles(dirPath))
{
if (mCancelling)
return;
var fileName = scope String();
fileEntry.GetFileName(fileName);
if (PassesFilter(fileName, searchOptions))
{
var filePath = new String();
fileEntry.GetFilePath(filePath);
var upperPath = new String(filePath);
IDEUtils.FixFilePath(upperPath);
if (!Environment.IsFileSystemCaseSensitive)
upperPath.ToUpper();
if (mFoundPathSet.Add(upperPath))
{
mSearchPaths.Add(filePath);
}
else
{
delete upperPath;
delete filePath;
}
}
}
if (searchOptions.mRecurseDirectories)
{
for (var dirEntry in Directory.EnumerateDirectories(dirPath))
{
if (mCancelling)
return;
var newDirPath = scope String();
dirEntry.GetFilePath(newDirPath);
AddFilesFromDirectory(newDirPath, searchOptions);
}
}
}
public void Search(SearchOptions searchOptions)
{
if (mSearchThread != null)
StopSearch();
mCancelling = false;
Clear();
QueueLine("Searching...");
mSearchPaths = new List<String>();
mFoundPathSet = new HashSet<String>();
if (searchOptions.mSearchLocation == sEntireSolution)
{
for (var project in IDEApp.sApp.mWorkspace.mProjects)
{
AddFromFilesFolder(project.mRootFolder, searchOptions);
}
}
else if (searchOptions.mSearchLocation == sCurrentDocument)
{
var sourceViewPanel = gApp.GetActiveSourceViewPanel(true);
if (sourceViewPanel != null)
{
mSearchPaths.Add(new String(sourceViewPanel.mFilePath));
}
}
else if (searchOptions.mSearchLocation == sCurrentProject)
{
var sourceViewPanel = gApp.GetActiveSourceViewPanel(true);
if (sourceViewPanel != null)
{
if (sourceViewPanel.mProjectSource != null)
AddFromFilesFolder(sourceViewPanel.mProjectSource.mProject.mRootFolder, searchOptions);
}
}
else
{
searchOptions.mDeferredFindFiles = true;
}
for (var filePath in mSearchPaths)
{
String fileText = null;
var editData = gApp.GetEditData(filePath, false, false);
if (editData != null)
{
if (editData.mEditWidget != null)
{
fileText = new String();
editData.mEditWidget.GetText(fileText);
}
else if (editData.mSavedContent != null)
{
fileText = new String();
fileText.Append(editData.mSavedContent);
}
}
if (fileText != null)
{
FindInfo findInfo = new FindInfo();
findInfo.mContent = fileText;
mFindInfoMap[filePath] = findInfo;
}
}
if (searchOptions.mDeferredFindFiles)
{
String dirPath = scope String(searchOptions.mSearchLocation);
IDEUtils.FixFilePath(dirPath);
if (!dirPath.EndsWith(Path.DirectorySeparatorChar))
dirPath.Append(Path.DirectorySeparatorChar);
using (gApp.mMonitor.Enter())
{
for (let kv in gApp.mFileEditData)
{
if (kv.key.StartsWith(dirPath, Environment.IsFileSystemCaseSensitive ? .Ordinal : .OrdinalIgnoreCase))
{
let editData = kv.value;
if (!PassesFilter(editData.mFilePath, searchOptions))
continue;
String fileText = null;
if (editData.mEditWidget != null)
{
fileText = new String();
editData.mEditWidget.GetText(fileText);
}
else if (editData.mSavedContent != null)
{
fileText = new String();
fileText.Append(editData.mSavedContent);
}
if (fileText != null)
{
let filePath = new String(editData.mFilePath);
FindInfo findInfo = new FindInfo();
findInfo.mContent = fileText;
mFindInfoMap[filePath] = findInfo;
mSearchPaths.Add(filePath);
mFoundPathSet.Add(new String(kv.key));
}
}
}
}
}
mSearchOptions = searchOptions;
mSearchThread = new Thread(new => SearchThread);
mSearchThread.Start(false);
}
public override void Serialize(StructuredData data)
{
data.Add("Type", "FindResultsPanel");
}
public override bool Deserialize(StructuredData data)
{
return base.Deserialize(data);
}
public void QueueLine(String text)
{
mCurLineNum++;
using (mMonitor.Enter())
mPendingLines.Add(new String(text));
}
void RecordLineData(int32 ouputLineNum, FileEditData fileEditData)
{
}
public void QueueLine(FileEditData fileEditData, int32 line, int32 lineChar, String lineStr)
{
RecordLineData(mCurLineNum, fileEditData);
int charId = -1;
if (fileEditData.mEditWidget != null)
{
let editWidgetContent = fileEditData.mEditWidget.mEditWidgetContent;
int textIdx = editWidgetContent.GetTextIdx(line, lineChar);
charId = editWidgetContent.mData.mTextIdData.GetIdAtIndex(textIdx);
}
else
{
mHasUnboundLineSrcInfos = true;
}
while (mCurLineNum >= mLineSrcInfo.Count)
mLineSrcInfo.Add(null);
var lineSrcInfo = new LineSrcInfo();
lineSrcInfo.mCharId = (int32)charId;
lineSrcInfo.mEditData = fileEditData;
lineSrcInfo.mLine = line;
lineSrcInfo.mLineChar = lineChar;
mLineSrcInfo[mCurLineNum] = lineSrcInfo;
String outStr = scope String();
outStr.AppendF("{0}({1}):{2}", fileEditData.mFilePath, line + 1, lineStr);
gApp.mFindResultsPanel.QueueLine(outStr);
}
public void QueueLine(String fileName, int32 line, int32 column, String text)
{
QueueLine(gApp.GetEditData(fileName, true, false), line, column, text);
}
public override void Update()
{
base.Update();
// Try to bind locations to charIds if new files have been loaded
if ((mHasUnboundLineSrcInfos) && (mLastEditDataRevision != IDEApp.sApp.mFileDataDataRevision))
{
mHasUnboundLineSrcInfos = false;
for (var lineSrcInfo in mLineSrcInfo)
{
if (lineSrcInfo == null)
continue;
if (lineSrcInfo.mCharId != -1)
continue;
if (lineSrcInfo.mEditData.mEditWidget == null)
{
mHasUnboundLineSrcInfos = true;
continue;
}
let editWidgetContent = lineSrcInfo.mEditData.mEditWidget.mEditWidgetContent;
int textIdx = editWidgetContent.GetTextIdx(lineSrcInfo.mLine, lineSrcInfo.mLineChar);
lineSrcInfo.mCharId = (int32)editWidgetContent.mData.mTextIdData.GetIdAtIndex((int32)textIdx);
}
mLastEditDataRevision = IDEApp.sApp.mFileDataDataRevision;
}
using (mMonitor.Enter())
{
if (mPendingLines.Count > 0)
{
String sb = scope String();
while (mPendingLines.Count > 0)
{
var pendingLine = mPendingLines.PopFront();
sb.Append(pendingLine, "\n");
delete pendingLine;
}
Write(sb);
}
}
if ((mSearchThread != null) && (mSearchThread.Join(0)))
{
if (!mDeferredReplacePaths.IsEmpty)
{
GlobalUndoData globalUndoData = gApp.mGlobalUndoManager.CreateUndoData();
int replaceCount = 0;
for (var filePath in mDeferredReplacePaths)
{
int replaceInFileCount = 0;
var editData = gApp.GetEditData(filePath);
globalUndoData.mFileEditDatas.Add(editData);
var sourceEditBatchHelper = scope:: SourceEditBatchHelper(editData.mEditWidget, "#renameSymbol", new GlobalUndoAction(editData, globalUndoData));
bool matchCase = mSearchOptions.mMatchCase;
let editWidgetContent = editData.mEditWidget.mEditWidgetContent;
let data = editData.mEditWidget.mEditWidgetContent.mData;
//let searchStrPtr = mSearchOptions.mSearchString.Ptr;
bool isNewStart = true;
//for (int i = 0; i < data.mTextLength - mSearchOptions.mSearchString.Length; i++)
int i = 0;
while (i < data.mTextLength - mSearchOptions.mSearchString.Length)
{
if ((isNewStart) || (!mSearchOptions.mMatchWholeWord))
{
bool matches = true;
int searchOfs = 0;
while (searchOfs < mSearchOptions.mSearchString.Length)
{
var (checkC, charBytes) = editWidgetContent.GetChar32(i + searchOfs);
char32 searchC = mSearchOptions.mSearchString.GetChar32(searchOfs).c;
if (!matchCase)
{
checkC = checkC.ToUpper;
searchC = searchC.ToUpper;
}
if (checkC != searchC)
{
matches = false;
break;
}
searchOfs += charBytes;
}
if ((matches) && (mSearchOptions.mMatchWholeWord))
{
int nextIdx = i + mSearchOptions.mSearchString.Length;
if (nextIdx < data.mTextLength)
{
var nextC = editWidgetContent.GetChar32(nextIdx).0;
if (IsWordChar(nextC))
matches = false;
}
}
if (matches)
{
editWidgetContent.CursorTextPos = i;
editWidgetContent.mSelection = EditSelection(i, i + mSearchOptions.mSearchString.Length);
var insertTextAction = new EditWidgetContent.InsertTextAction(editWidgetContent, mSearchOptions.mReplaceString, .None);
insertTextAction.mMoveCursor = false;
editWidgetContent.mData.mUndoManager.Add(insertTextAction);
editWidgetContent.PhysDeleteSelection(false);
editWidgetContent.PhysInsertAtCursor(mSearchOptions.mReplaceString, false);
i += mSearchOptions.mSearchString.Length - 1;
replaceCount++;
replaceInFileCount++;
}
}
var (c32, charBytes) = editWidgetContent.GetChar32(i);
if (mSearchOptions.mMatchWholeWord)
isNewStart = !IsWordChar(c32);
i += charBytes;
}
sourceEditBatchHelper.Finish();
if ((IDEApp.IsBeefFile(filePath)) && (gApp.mBfResolveCompiler != null))
{
for (var projectSource in editData.mProjectSources)
gApp.mBfResolveCompiler.QueueProjectSource(projectSource);
gApp.mBfResolveCompiler.QueueDeferredResolveAll();
}
var line = scope String();
line.AppendF(" {0}: Replaced {1} instance{2}\n", filePath, replaceInFileCount, (replaceInFileCount == 1) ? "" : "s");
Write(line);
}
}
StopSearch();
}
}
public override void Clear()
{
base.Clear();
ClearAndDeleteItems(mLineSrcInfo);
mHasUnboundLineSrcInfos = false;
mCurLineNum = 0;
}
public override bool HasAffinity(Widget otherPanel)
{
return base.HasAffinity(otherPanel) || (otherPanel is OutputPanel);
}
}
}

View file

@ -0,0 +1,151 @@
using Beefy.theme.dark;
using Beefy.widgets;
using Beefy.gfx;
using System;
using System.Collections.Generic;
using IDE.Debugger;
namespace IDE.ui
{
class GoToAddressDialog : IDEDialog
{
MemoryPanel mMemoryPanel;
ExpressionEditWidget mAddressEdit;
String mExpr ~ delete _;
public bool mIsPending;
public this()
{
Title = "Go To Address";
}
public override void CalcSize()
{
mWidth = GS!(320);
mHeight = GS!(100);
}
void HandleResult(String val)
{
//String evalStr = mExpr;
if (val.StartsWith("!", StringComparison.Ordinal))
{
String errorString = scope String();
DebugManager.GetFailString(val, mExpr, errorString);
IDEApp.sApp.Fail(errorString);
return;
}
var vals = scope List<StringView>(val.Split('\n'));
let addr = (int)int64.Parse(scope String(vals[0]), System.Globalization.NumberStyles.HexNumber);
let byteCount = int32.Parse(scope String(vals[1])).Get();
mMemoryPanel.mBinaryDataWidget.SelectRange(addr, byteCount);
Close();
}
void GetAddress()
{
var sourceEditWidgetContent = (SourceEditWidgetContent)mAddressEdit.Content;
if (sourceEditWidgetContent.mAutoComplete != null)
sourceEditWidgetContent.KeyChar('\t');
delete mExpr;
mExpr = new String();
mAddressEdit.GetText(mExpr);
mExpr.Trim();
String val = scope String();
let result = gApp.DebugEvaluate(null, mExpr, val, -1, .NotSet, .MemoryAddress | .AllowSideEffects | .AllowCalls, new => HandleResult);
if (result == .Pending)
{
mIsPending = true;
mDefaultButton.mDisabled = true;
}
else
{
HandleResult(val);
}
}
public void Init(MemoryPanel memoryPanel)
{
mMemoryPanel = memoryPanel;
mDefaultButton = AddButton("Go", new (evt) => { GetAddress(); evt.mCloseDialog = false; } );
mEscButton = AddButton("Cancel", new (evt) => Close());
//mNameEdit = AddEdit("NewProject");
//mDirectoryEdit = AddEdit(IDEApp.sApp.mWorkspace.mDir);
mAddressEdit = new ExpressionEditWidget();
mAddressEdit.mIsAddress = true;
AddWidget(mAddressEdit);
mTabWidgets.Add(mAddressEdit);
//mAddressEdit.
mAddressEdit.mOnSubmit.Add(new => EditSubmitHandler);
mAddressEdit.mOnCancel.Add(new => EditCancelHandler);
}
public override void PopupWindow(WidgetWindow parentWindow, float offsetX = 0, float offsetY = 0)
{
base.PopupWindow(parentWindow, offsetX, offsetY);
mAddressEdit.SetFocus();
}
public override void ResizeComponents()
{
base.ResizeComponents();
float curY = mHeight - GS!(20) - mButtonBottomMargin;
//mAddressEdit.Resize(GS!(16), curY - GS!(36), mWidth - GS!(16) * 2, GS!(28));
mAddressEdit.ResizeAround(GS!(16), curY - GS!(36), mWidth - GS!(16)*2);
//curY -= 50;
//mAddressEdit.Resize(16, curY - 36, mWidth - 16 * 2, 20);
}
public override void Draw(Graphics g)
{
base.Draw(g);
g.DrawString("Memory Address", mAddressEdit.mX, mAddressEdit.mY - GS!(20));
//g.DrawString("Project Directory", mDialogEditWidget.mX, mDialogEditWidget.mY - 20);
}
void SetPending(bool isPending)
{
mIsPending = isPending;
if (isPending)
{
SetFocus();
mAddressEdit.Content.mIsReadOnly = true;
mDefaultButton.mDisabled = true;
}
else
{
mAddressEdit.Content.mIsReadOnly = false;
mDefaultButton.mDisabled = false;
}
}
public override void Close()
{
base.Close();
if (mIsPending)
gApp.mBreakpointPanel.CancelPending();
}
public override void Update()
{
base.Update();
if ((mIsPending) && (gApp.mPendingDebugExprHandler == null))
{
SetPending(false);
}
}
}
}

View file

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.widgets;
using Beefy.theme.dark;
using Beefy.gfx;
using Beefy.events;
namespace IDE.ui
{
class GoToLineDialog : DarkDialog
{
SourceViewPanel mSourceViewPanel;
int mCursorPos;
double mVertPos;
public this(String title = null, String text = null, Image icon = null) :
base(title, text, icon)
{
}
public void Init(SourceViewPanel sourceViewPanel)
{
mSourceViewPanel = sourceViewPanel;
int line;
int lineChar;
mSourceViewPanel.mEditWidget.Content.GetCursorLineChar(out line, out lineChar);
mCursorPos = sourceViewPanel.mEditWidget.Content.CursorTextPos;
mVertPos = sourceViewPanel.mEditWidget.mVertPos.mDest;
mDefaultButton = AddButton("OK", new (evt) => GotoLineSubmit(true));
mEscButton = AddButton("Cancel", new (evt) => Cancel());
var editWidget = AddEdit(StackStringFormat!("{0}", line + 1));
editWidget.mOnContentChanged.Add(new (evt) => GotoLineSubmit(false));
}
void GotoLineSubmit(bool isFinal)
{
var editWidgetContent = mSourceViewPanel.mEditWidget;
var text = scope String();
mDialogEditWidget.GetText(text);
var lineResult = int32.Parse(text);
//if (!lineResult.Failed(true))
if (lineResult case .Ok(var line))
{
line--;
if ((line < 0) || (line >= editWidgetContent.Content.GetLineCount()))
{
IDEApp.Beep(IDEApp.MessageBeepType.Error);
return;
}
int column = ((SourceEditWidgetContent)editWidgetContent.Content).GetLineEndColumn(line, false, true, true);
editWidgetContent.Content.CursorLineAndColumn = EditWidgetContent.LineAndColumn(line, column);
editWidgetContent.Content.CursorMoved();
editWidgetContent.Content.EnsureCursorVisible(true, true);
if (isFinal)
{
editWidgetContent.Content.mSelection = null;
mSourceViewPanel.RecordHistoryLocation();
}
else
{
int lineStart;
int lineEnd;
editWidgetContent.Content.GetLinePosition(line, out lineStart, out lineEnd);
editWidgetContent.Content.mSelection = EditSelection(lineStart, lineEnd + 1);
}
}
}
void Cancel()
{
var editWidgetContent = mSourceViewPanel.mEditWidget;
editWidgetContent.Content.mSelection = null;
mSourceViewPanel.mEditWidget.Content.CursorTextPos = mCursorPos;
mSourceViewPanel.mEditWidget.mVertPos.Set(mVertPos);
}
}
}

1624
IDE/src/ui/HoverWatch.bf Normal file

File diff suppressed because it is too large Load diff

140
IDE/src/ui/IDEDialog.bf Normal file
View file

@ -0,0 +1,140 @@
using Beefy.theme.dark;
using Beefy.widgets;
using IDE.util;
using System;
using Beefy.gfx;
namespace IDE.ui
{
class IDEDialog : DarkDialog
{
public DarkButton mPrevButton;
public DarkButton mNextButton;
public SettingHistoryManager mSettingHistoryManager;
public void CreatePrevNextButtons()
{
mPrevButton = new DarkButton();
mPrevButton.Label = "< &Prev";
AddDialogComponent(mPrevButton);
mPrevButton.mOnMouseClick.Add(new (btn) =>
{
var propBag = mSettingHistoryManager.GetPrev();
if (propBag != null)
UseProps(propBag);
UpdateHistory();
});
/*mPrevButton = AddButton("< &Prev", new (btn) =>
{
});*/
mNextButton = new DarkButton();
mNextButton.Label = "&Next >";
AddDialogComponent(mNextButton);
mNextButton.mOnMouseClick.Add(new (btn) =>
{
var propBag = mSettingHistoryManager.GetNext();
if (propBag != null)
UseProps(propBag);
UpdateHistory();
});
/*mMatchCaseCheckbox = new DarkCheckBox();
mMatchCaseCheckbox.Label = "Match &case";
AddDialogComponent(mMatchCaseCheckbox);*/
UpdateHistory();
}
public override void AddedToParent()
{
base.AddedToParent();
RehupMinSize();
}
protected virtual void RehupMinSize()
{
if (mWidgetWindow.mWindowFlags.HasFlag(.Resizable))
mWidgetWindow.SetMinimumSize(GS!(240), GS!(180), true);
}
public override void RehupScale(float oldScale, float newScale)
{
base.RehupScale(oldScale, newScale);
RehupMinSize();
}
protected virtual void UseProps(PropertyBag propBag)
{
}
public override void Close()
{
base.Close();
if (mSettingHistoryManager != null)
mSettingHistoryManager.ToEnd();
}
protected void UpdateHistory()
{
mPrevButton.mDisabled = !mSettingHistoryManager.HasPrev();
mNextButton.mDisabled = !mSettingHistoryManager.HasNext();
}
public override void ResizeComponents()
{
base.ResizeComponents();
if (mPrevButton != null)
{
mPrevButton.Resize(mWidth - GS!(64)*2 - GS!(6) - GS!(4), 6, GS!(64), GS!(22));
mNextButton.Resize(mWidth - GS!(64) - GS!(6), 6, GS!(64), GS!(22));
}
}
public override void Escape()
{
if ((let editWidget = mWidgetWindow.mFocusWidget as EditWidget) && (let ewc = editWidget.mEditWidgetContent as SourceEditWidgetContent))
{
if ((ewc.mAutoComplete != null) && (ewc.mAutoComplete.IsShowing()))
{
ewc.mAutoComplete.Close();
return;
}
}
base.Escape();
}
public override bool HandleTab(int dir)
{
if ((let editWidget = mWidgetWindow.mFocusWidget as EditWidget) && (let ewc = editWidget.mEditWidgetContent as SourceEditWidgetContent))
{
if ((ewc.mAutoComplete != null) && (ewc.mAutoComplete.IsShowing()))
{
//ewc.KeyChar('\t');
return false;
}
}
return base.HandleTab(dir);
}
public override void Submit()
{
if ((mDefaultButton != null) && (mDefaultButton.mDisabled))
{
IDEApp.Beep(.Error);
return;
}
base.Submit();
}
public void DrawLabel(Graphics g, Widget widget, StringView label)
{
g.DrawString(label, widget.mX, widget.mY - GS!(18));
}
}
}

105
IDE/src/ui/IDEListView.bf Normal file
View file

@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy.gfx;
using Beefy.geom;
using Beefy.theme.dark;
using Beefy.widgets;
using Beefy.events;
namespace IDE.ui
{
public class IDEListViewItem : DarkListViewItem
{
}
public class IDEListView : DarkListView
{
public bool mCancelingEdit;
public ListViewItem mEditingItem;
public Event<delegate void(EditWidget editWidget, bool cancelled)> mOnEditDone ~ _.Dispose();
public SingleLineEditWidget mEditWidget;
//public delegate void DoneEvent(EditWidget editWidget, bool cancelled);
//public Event<DoneEvent> mOnEditDone;
public this()
{
mAutoFocus = true;
}
protected override ListViewItem CreateListViewItem()
{
var anItem = new IDEListViewItem();
return anItem;
}
public void EditListViewItem(ListViewItem listViewItem)
{
mCancelingEdit = false;
mEditingItem = (DarkListViewItem)listViewItem;
SingleLineEditWidget editWidget = new SingleLineEditWidget();
mEditWidget = editWidget;
editWidget.SetText(listViewItem.mLabel);
editWidget.Content.SelectAll();
ResizeComponents();
AddWidget(editWidget);
editWidget.mOnLostFocus.Add(new => HandleEditLostFocus);
editWidget.mOnSubmit.Add(new => HandleRenameSubmit);
editWidget.mOnCancel.Add(new => HandleRenameCancel);
editWidget.SetFocus();
}
void HandleEditLostFocus(Widget widget)
{
EditWidget editWidget = (EditWidget)widget;
editWidget.mOnLostFocus.Remove(scope => HandleEditLostFocus, true);
editWidget.mOnSubmit.Remove(scope => HandleRenameSubmit, true);
editWidget.mOnCancel.Remove(scope => HandleRenameCancel, true);
mOnEditDone(editWidget, mCancelingEdit);
mEditWidget = null;
editWidget.RemoveSelf();
gApp.DeferDelete(editWidget);
}
void HandleRenameCancel(EditEvent theEvent)
{
mCancelingEdit = true;
HandleEditLostFocus((EditWidget)theEvent.mSender);
}
void HandleRenameSubmit(EditEvent theEvent)
{
HandleEditLostFocus((EditWidget)theEvent.mSender);
}
void ResizeComponents()
{
if (mEditWidget != null)
{
let listViewItem = mEditingItem;
float aX;
float aY;
listViewItem.SelfToOtherTranslate(this, 0, 0, out aX, out aY);
aY += GS!(0);
aX = listViewItem.LabelX - GS!(4);
float aWidth = mWidth - aX - GS!(20);
mEditWidget.ResizeAround(aX, aY, aWidth);
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
}
}

View file

@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy.widgets;
using Beefy.utils;
using Beefy.theme.dark;
using System.Diagnostics;
namespace IDE.ui
{
public class ImmediatePanel : TextPanel
{
ImmediateWidget mImmediateWidget;
bool mHasResult;
String mQueuedText = new String() ~ delete _;
public override SourceEditWidget EditWidget
{
get
{
return mImmediateWidget;
}
}
public this()
{
mImmediateWidget = new ImmediateWidget();
mImmediateWidget.mPanel = this;
mImmediateWidget.InitScrollbars(true, true);
var darkEditContent = (ImmediateWidgetContent)mImmediateWidget.Content;
darkEditContent.mOnEscape = new () => EscapeHandler();
darkEditContent.mFont = IDEApp.sApp.mCodeFont;
//darkEditContent.mFont = DarkTheme.sDarkTheme.mSmallFont;
AddWidget(mImmediateWidget);
mImmediateWidget.StartEntry();
}
public override void Serialize(StructuredData data)
{
base.Serialize(data);
data.Add("Type", "ImmediatePanel");
}
public override bool Deserialize(StructuredData data)
{
return base.Deserialize(data);
}
public override void Clear()
{
if ((mImmediateWidget.mInfoButton != null) && (mImmediateWidget.mInfoButton.mParent != null))
{
mImmediateWidget.mInfoButton.RemoveSelf();
}
mImmediateWidget.SetText("");
mImmediateWidget.StartEntry();
var editWidgetContent = (ImmediateWidgetContent)mImmediateWidget.mEditWidgetContent;
if (editWidgetContent.mAutoComplete != null)
editWidgetContent.mAutoComplete.Close();
}
public void Write(String text)
{
//mImmediateWidget.Content.AppendText(text);
mQueuedText.Append(text);
}
public void WriteResult(String text)
{
//mImmediateWidget.Content.AppendText(text);
//mImmediateWidget.Content.CursorToEnd();
mHasResult = true;
Write(text);
}
public void GotoNextError()
{
var content = (ImmediateWidgetContent)mImmediateWidget.Content;
int curLine;
int lineChar;
content.GetLineCharAtIdx(content.CursorTextPos, out curLine, out lineChar);
int32 lineCount = content.GetLineCount();
for (int lineOfs = 1; lineOfs < lineCount + 1; lineOfs++)
{
int lineIdx = (curLine + lineOfs) % lineCount;
if (content.GotoRefrenceAtLine(lineIdx))
break;
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
mImmediateWidget.Resize(0, 0, width, height);
}
void UpdateMouseover()
{
if (!CheckAllowHoverWatch())
return;
if ((mImmediateWidget.mInfoButton != null) && (mImmediateWidget.mInfoButton.IsOnLine()))
return;
if (IDEApp.sApp.HasPopupMenus())
return;
if ((mHoverWatch != null) && (mHoverWatch.mCloseDelay == 0))
mHoverWatch.Close();
}
public override bool EscapeHandler()
{
if (base.EscapeHandler())
return true;
mImmediateWidget.ClearEntry();
return true;
}
public override void SetFocus()
{
base.SetFocus();
var content = (ImmediateWidgetContent)mImmediateWidget.Content;
content.MoveCursorToIdx(content.mData.mTextLength);
}
public override void Update()
{
base.Update();
UpdateMouseover();
if (mQueuedText.Length > 0)
{
scope AutoBeefPerf("OutputPanel.Update:QueuedText");
var editData = mImmediateWidget.mEditWidgetContent.mData;
int line;
int lineChar;
mImmediateWidget.Content.GetLineCharAtIdx(mImmediateWidget.Content.mData.mTextLength, out line, out lineChar);
mImmediateWidget.Content.mAutoHorzScroll = false;
int32 startLen = editData.mTextLength;
mImmediateWidget.Content.AppendText(mQueuedText);
mImmediateWidget.Content.mAutoHorzScroll = true;
Debug.Assert(editData.mTextLength == startLen + mQueuedText.Length);
mQueuedText.Clear();
}
/*if (mHasResult)
{
mHasResult = false;
mImmediateWidget.Content.CursorToEnd();
}*/
}
public override bool HasAffinity(Widget otherPanel)
{
return base.HasAffinity(otherPanel) || (otherPanel is OutputWidget);
}
public void GetQuickExpression(String expr)
{
if (mImmediateWidget.GetCmdText(expr))
return;
if (!mImmediateWidget.mHistoryList.IsEmpty)
expr.Append(mImmediateWidget.mHistoryList.Back);
}
}
}

View file

@ -0,0 +1,693 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy.widgets;
using Beefy.theme.dark;
using Beefy.gfx;
using System.Diagnostics;
using System.IO;
namespace IDE.ui
{
public class ImmediateWidgetContent : OutputWidgetContent
{
bool mSkipCheckSelection;
public this()
{
mIsReadOnly = false;
mAllowVirtualCursor = false;
mIsMultiline = true;
//mWordWrap = true;
}
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
{
if ((btn == 0) && (btnCount > 1))
{
for (int32 lineOfs = 0; lineOfs >= -1; lineOfs--)
if (GotoRefrenceAtLine(CursorLineAndColumn.mLine, lineOfs))
return;
}
base.MouseDown(x, y, btn, btnCount);
}
public override void Draw(Graphics g)
{
base.Draw(g);
ImmediateWidget watchEditWidget = (ImmediateWidget)mEditWidget;
if (watchEditWidget.mErrorEnd != 0)
{
var text = scope String();
watchEditWidget.GetText(text);
//float indent = mTextInsets.mLeft;
//float strStarts = indent + g.mFont.GetWidth(text.Substring(0, watchEditWidget.mErrorStart));
//float strEnds = indent + g.mFont.GetWidth(text.Substring(0, Math.Min(watchEditWidget.mErrorEnd, text.Length)));
float startX;
float startY;
float endX;
float endY;
int line;
int lineChar;
GetLineCharAtIdx(watchEditWidget.mErrorStart, out line, out lineChar);
GetTextCoordAtLineChar(line, lineChar, out startX, out startY);
GetLineCharAtIdx(watchEditWidget.mErrorEnd, out line, out lineChar);
GetTextCoordAtLineChar(line, lineChar, out endX, out endY);
using (g.PushColor(0xFFFF4040))
IDEApp.sApp.DrawSquiggle(g, startX, startY, endX - startX);
}
//TEST:
/*g.SetFont(IDEApp.sApp.mCodeFont);
using (g.PushColor(0xFFFFFFFF))
g.FillRect(0, 0, 200, 50);
using (g.PushColor(0xFF000000))
{
g.DrawString("Hey Bro, goofy man!", 4, 4);
}
using (g.PushColor(0xFF000000))
g.FillRect(0, 50, 200, 50);
using (g.PushColor(0xFFFFFFFF))
{
g.DrawString("Hey Bro, goofy man!", 4, 50 + 4);
}*/
}
bool IsInsideEntry(int idx)
{
var immediateWidget = (ImmediateWidget)mEditWidget;
return idx > immediateWidget.mEntryStartPos.mIndex;
}
void CheckSelection()
{
if ((mSelection != null) && (!mSkipCheckSelection))
{
if ((!IsInsideEntry(mSelection.Value.MinPos) && (IsInsideEntry(mSelection.Value.MaxPos))))
{
var immediateWidget = (ImmediateWidget)mEditWidget;
mSelection = EditSelection(immediateWidget.mEntryStartPos.mIndex + 1, mSelection.Value.MaxPos);
}
if ((!IsInsideEntry(mSelection.Value.mStartPos)) || (!IsInsideEntry(mSelection.Value.mEndPos)))
return;
}
}
public override void DeleteSelection(bool moveCursor)
{
CheckSelection();
base.DeleteSelection();
}
public override void ClearText()
{
mSkipCheckSelection = true;
base.ClearText();
mSkipCheckSelection = false;
var immediateWidget = mEditWidget as ImmediateWidget;
immediateWidget.ClearEntry();
immediateWidget.HandleResult(scope String(""));
}
public override void Backspace()
{
if (!IsInsideEntry(mCursorTextPos - 1))
return;
base.Backspace();
}
public override bool CheckReadOnly()
{
var immediateWidget = (ImmediateWidget)mEditWidget;
if (immediateWidget.mChangeInvalidatesHistory)
immediateWidget.mHistoryIdx = -1;
CheckSelection();
if (!IsInsideEntry(mCursorTextPos))
{
mSelection = null;
MoveCursorToIdx(mData.mTextLength);
}
return base.CheckReadOnly();
}
public override void CursorToLineStart(bool allowToScreenStart)
{
if (IsInsideEntry(CursorTextPos))
{
var immediateWidget = (ImmediateWidget)mEditWidget;
MoveCursorToIdx(immediateWidget.mEntryStartPos.mIndex + 1);
return;
}
base.CursorToLineStart(allowToScreenStart);
}
public override bool PrepareForCursorMove(int dir = 0)
{
if (dir == -1)
{
var immediateWidget = (ImmediateWidget)mEditWidget;
if (CursorTextPos == immediateWidget.mEntryStartPos.mIndex + 1)
return true;
}
return base.PrepareForCursorMove(dir);
}
}
public class ImmediateInfoButton : Widget
{
public ImmediateWidget mImmediateWidget;
public this()
{
}
public ~this()
{
}
public override void Draw(Graphics g)
{
g.Draw(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.MoreInfo));
}
public override void MouseEnter()
{
base.MouseEnter();
if (mImmediateWidget.mPanel.mHoverWatch != null)
mImmediateWidget.mPanel.mHoverWatch.Close();
var hoverWatch = new HoverWatch();
hoverWatch.mAllowLiterals = true;
hoverWatch.mAllowSideEffects = true;
hoverWatch.mOrigEvalString.Set(mImmediateWidget.mResultHoverWatch.mOrigEvalString);
hoverWatch.SetListView(mImmediateWidget.mResultHoverWatch.mListView);
hoverWatch.Show(mImmediateWidget.mPanel, mX + GS!(2), mY + GS!(3), null);
hoverWatch.mRehupEvent.Add(new () =>
{
mImmediateWidget.RehupResult();
});
mImmediateWidget.mPanel.mHoverWatch = hoverWatch;
}
public bool IsOnLine()
{
if (mWidgetWindow == null)
return false;
float rootX;
float rootY;
SelfToRootTranslate(0, 0, out rootX, out rootY);
return (mWidgetWindow.mHasMouseInside) && (mWidgetWindow.mMouseY >= rootY) && (mWidgetWindow.mMouseY < rootY + mHeight) &&
(mWidgetWindow.mMouseX < rootX + GS!(80));
}
}
public class ImmediateWidget : SourceEditWidget
{
public PersistentTextPosition mEntryStartPos;
public int32 mErrorStart;
public int32 mErrorEnd;
int32 mLastTextVersionId;
public bool mWasTextModified;
public bool mIsAddress;
public bool mChangeInvalidatesHistory = true;
public List<String> mHistoryList = new List<String>() ~ DeleteContainerAndItems!(_);
public int32 mHistoryIdx = -1;
public bool mUsedHistory = false;
public HoverWatch mResultHoverWatch ~ delete _;
public HoverWatch mPendingHoverWatch ~ delete _;
public ImmediateInfoButton mInfoButton;
public String mLastEvalString ~ delete _;
List<char32> mDeferredChars = new .() ~ delete _;
public bool IsPending
{
get
{
if (mResultHoverWatch == null)
return false;
if (mResultHoverWatch.mListView == null)
return false;
var listViewItem = (HoverWatch.HoverListViewItem)mResultHoverWatch.mListView.GetRoot().GetChildAtIndex(0);
return listViewItem.mWatchEntry.mIsPending;
}
}
public this()
: base(null, new ImmediateWidgetContent())
{
var editWidgetContent = (ImmediateWidgetContent)mEditWidgetContent;
editWidgetContent.mOnGenerateAutocomplete = new (char, options) => UpdateText(true);
mEntryStartPos = new PersistentTextPosition(0);
editWidgetContent.PersistentTextPositions.Add(mEntryStartPos);
}
public ~this()
{
if (mInfoButton != null)
{
if (mInfoButton.mParent != null)
mInfoButton.RemoveSelf();
delete mInfoButton;
}
}
public override void LostFocus()
{
base.LostFocus();
//var sourceEditWidgetContent = (SourceEditWidgetContent)mEditWidgetContent;
//TODO: This was causing autocomplete to close when you clicked on the scroll thumb. Why did we need this?
//if (sourceEditWidgetContent.mAutoComplete != null)
//sourceEditWidgetContent.mAutoComplete.Close();
}
public bool GetCmdText(String outCmd)
{
int32 len = mEditWidgetContent.mData.mTextLength - mEntryStartPos.mIndex - 1;
if (len <= 0)
return false;
mEditWidgetContent.ExtractString(mEntryStartPos.mIndex + 1, len, outCmd);
return true;
}
[AlwaysInclude]
public void ShowStr()
{
String str = scope String();
mEditWidgetContent.ExtractString(0, mEditWidgetContent.mData.mTextLength, str);
}
public void HandleResult(String cmdText)
{
/*var root = (HoverWatch.HoverListViewItem)mResultHoverWatch.mListView.GetRoot();
HoverWatch.HoverListViewItem result = null;
if (root.GetChildCount() > 0)
result = (HoverWatch.HoverListViewItem)root.GetChildAtIndex(0);*/
mEditWidgetContent.CursorToEnd();
if (mResultHoverWatch != null)
delete mResultHoverWatch;
mResultHoverWatch = new HoverWatch();
mResultHoverWatch.mAllowLiterals = true;
mResultHoverWatch.mAllowSideEffects = true;
HoverWatch.HoverListViewItem result = null;
if (cmdText == null)
{
// Is a continuation
if (mLastEvalString != null)
result = mResultHoverWatch.Eval(mLastEvalString, true);
gApp.mIsImmediateDebugExprEval = true;
}
else
{
cmdText.Trim();
if (cmdText == "cls")
{
mEditWidgetContent.ClearText();
return;
}
if (cmdText.Length > 0)
{
if ((mHistoryList.Count == 0) || (mHistoryList[mHistoryList.Count - 1] != cmdText))
mHistoryList.Add(new String(cmdText));
mUsedHistory = false;
if (cmdText.StartsWith("%"))
{
StringStream strStream = scope .(StringView(cmdText, 1), .Reference);
StreamReader reader = scope .(strStream);
gApp.mScriptManager.Clear();
gApp.mScriptManager.QueueCommands(reader, "Immediate");
}
else
result = mResultHoverWatch.Eval(cmdText, false);
mLastTextVersionId = mEditWidgetContent.mData.mCurTextVersionId;
gApp.mIsImmediateDebugExprEval = true;
}
}
if (result != null)
{
if (result.mWatchEntry.mIsPending)
{
if (cmdText != null)
{
delete mLastEvalString;
mLastEvalString = new String(cmdText);
}
//delete mPendingHoverWatch;
mEditWidgetContent.mIsReadOnly = true;
return;
}
IDEApp.sApp.MemoryEdited();
}
delete mLastEvalString;
mLastEvalString = null;
mEditWidgetContent.mIsReadOnly = false;
float resultX;
float resultY;
mEditWidgetContent.GetTextCoordAtCursor(out resultX, out resultY);
int32 startPos = mEditWidgetContent.mData.mTextLength;
if (result != null)
{
var subItemLabel = result.GetSubItem(1).mLabel;
if (subItemLabel == null)
subItemLabel = "";
mEditWidgetContent.AppendText(scope String(" ", subItemLabel, "\n"));
if (result.mWatchEntry.mWarnings != null)
{
int32 warnStart = mEditWidgetContent.mData.mTextLength;
for (var warning in result.mWatchEntry.mWarnings)
{
mEditWidgetContent.AppendText(" ");
mEditWidgetContent.AppendText(warning);
mEditWidgetContent.AppendText("\n");
}
for (int32 i = warnStart; i < mEditWidgetContent.mData.mTextLength; i++)
mEditWidgetContent.mData.mText[i].mDisplayTypeId = (uint8)SourceElementType.BuildWarning;
}
}
if (mInfoButton != null)
{
if (mInfoButton.mParent != null)
mInfoButton.RemoveSelf();
}
else
{
mInfoButton = new ImmediateInfoButton();
mInfoButton.mImmediateWidget = this;
}
if (result != null)
{
if (result.Failed)
{
for (int32 i = startPos; i < mEditWidgetContent.mData.mTextLength; i++)
mEditWidgetContent.mData.mText[i].mDisplayTypeId = (uint8)SourceElementType.Error;
}
else
{
mInfoButton.Resize(resultX - GS!(3), resultY - GS!(2), GS!(20), GS!(20));
mEditWidgetContent.AddWidget(mInfoButton);
}
}
//mEditWidgetContent.AppendText(vals[0] + "\n");
StartEntry();
}
public override void KeyChar(char32 c)
{
if (mEditWidgetContent.mIsReadOnly)
{
mDeferredChars.Add(c);
return;
}
String cmdText = scope String();
bool hasCmd = false;
mWasTextModified = true;
if ((c == '\r') || (c == '\n'))
{
//mChangeInvalidatesHistory = false;
//We removed this because we don't really want to autocomplete on ENTER
/*var editWidgetContent = (ImmediateWidgetContent)mEditWidgetContent;
if ((editWidgetContent.mAutoComplete != null) && (editWidgetContent.mAutoComplete.IsShowing()))
{
// Fake a 'tab' so it just completes
base.KeyChar('\t');
}*/
var editWidgetContent = (ImmediateWidgetContent)mEditWidgetContent;
if (editWidgetContent.mAutoComplete != null)
editWidgetContent.mAutoComplete.Close();
GetCmdText(cmdText);
hasCmd = true;
/*if (mEditWidgetContent.mText[mEditWidgetContent.mTextLength - 1].mChar == (byte)'\n')
hasCR = true;*/
//mChangeInvalidatesHistory = true;
}
else
{
//IDEApp.sApp.mBfResolveSystem.StartTiming();
base.KeyChar(c);
//IDEApp.sApp.mBfResolveSystem.StopTiming();
//IDEApp.sApp.mBfResolveSystem.DbgPrintTimings();
}
if (hasCmd)
{
mEditWidgetContent.AppendText("\n");
mEditWidgetContent.CursorTextPos = mEditWidgetContent.mData.mTextLength;
mEditWidgetContent.mIsReadOnly = true;
HandleResult(cmdText);
}
}
void SelectEntry()
{
mEditWidgetContent.mSelection = EditSelection(mEntryStartPos.mIndex + 1, mEditWidgetContent.mData.mTextLength);
mEditWidgetContent.CursorTextPos = mEntryStartPos.mIndex + 1;
}
public void ClearEntry()
{
SelectEntry();
mEditWidgetContent.DeleteSelection();
mHistoryIdx = -1;
mUsedHistory = false;
}
public override void KeyDown(KeyCode keyCode, bool isRepeat)
{
base.KeyDown(keyCode, isRepeat);
var editWidgetContent = (ImmediateWidgetContent)mEditWidgetContent;
if ((editWidgetContent.mAutoComplete != null) && (editWidgetContent.mAutoComplete.IsShowing()))
return;
/*if (keyCode == KeyCode.Escape)
{
ClearEntry();
}*/
if (((keyCode == KeyCode.Up) || (keyCode == KeyCode.Down)) && (mHistoryList.Count > 0))
{
if (mUsedHistory)
{
if (keyCode == KeyCode.Up)
mHistoryIdx = Math.Max(mHistoryIdx - 1, 0);
else
mHistoryIdx = Math.Min(mHistoryIdx + 1, (int32)mHistoryList.Count - 1);
}
else
mUsedHistory = true;
if (mHistoryIdx == -1)
mHistoryIdx = (int32)mHistoryList.Count - 1;
String command = mHistoryList[mHistoryIdx];
SelectEntry();
int32 cmdRevIdx = mHistoryIdx;
mEditWidgetContent.InsertAtCursor(command);
// Restore this, because InsertAtCursor sets mCommandRevIdx to -1
mHistoryIdx = cmdRevIdx;
}
}
public virtual void UpdateText(bool doAutoComplete)
{
if (mLastTextVersionId != 0)
mWasTextModified = true;
String val = scope String();
String cmdText = scope String();
GetCmdText(cmdText);
cmdText.Trim();
if (cmdText.Length > 0)
{
if (cmdText.StartsWith("%"))
{
// Do nothing
}
else
{
gApp.DebugEvaluate(null, cmdText, val, mEditWidgetContent.CursorTextPos - mEntryStartPos.mIndex - 2);
gApp.mIsImmediateDebugExprEval = true;
}
}
//var vals = String.StackSplit!(val, '\n');
var valEnum = val.Split('\n');
if (doAutoComplete)
{
var editWidgetContent = (ImmediateWidgetContent)mEditWidgetContent;
int32 idx = (int32)val.IndexOf(":autocomplete\n", false);
if (idx != -1)
{
if (editWidgetContent.mAutoComplete == null)
{
editWidgetContent.mAutoComplete = new AutoComplete(this);
editWidgetContent.mAutoComplete.mOnAutoCompleteInserted.Add(new () => UpdateText(true));
editWidgetContent.mAutoComplete.mOnClosed.Add(new () => { editWidgetContent.mAutoComplete = null; });
}
var info = scope String()..Append(val, idx + ":autocomplete\n".Length);
if (!editWidgetContent.mAutoComplete.mIsDocumentationPass)
editWidgetContent.mAutoComplete.SetInfo(info, true, mEntryStartPos.mIndex + 1);
}
else if (editWidgetContent.mAutoComplete != null)
editWidgetContent.mAutoComplete.Close();
}
mErrorStart = 0;
mErrorEnd = 0;
if (valEnum.MoveNext())
{
String result = scope String(valEnum.Current);
if (result.StartsWith("!", StringComparison.Ordinal))
{
result.Remove(0);
var errorVals = String.StackSplit!(result, '\t');
if (errorVals.Count > 1)
{
mErrorStart = int32.Parse(errorVals[0]).Get();
mErrorEnd = mErrorStart + int32.Parse(errorVals[1]).Get();
if (mErrorStart >= cmdText.Length)
{
// Just make it be the whole expression
mErrorStart = 0;
}
mErrorEnd = (int32)Math.Min(mErrorEnd, cmdText.Length);
int32 errOfs = mEntryStartPos.mIndex + 1;
mErrorStart += errOfs;
mErrorEnd += errOfs;
}
}
}
mLastTextVersionId = mEditWidgetContent.mData.mCurTextVersionId;
}
public override void RemovedFromParent(Widget previousParent, WidgetWindow previousWidgetWindow)
{
base.RemovedFromParent(previousParent, previousWidgetWindow);
var editWidgetContent = (ExpressionEditWidgetContent)mEditWidgetContent;
if (editWidgetContent.mAutoComplete != null)
editWidgetContent.mAutoComplete.Close();
}
public override void Update()
{
base.Update();
if ((mLastTextVersionId != mEditWidgetContent.mData.mCurTextVersionId) && (!IsPending))
{
UpdateText(false);
}
if (IDEApp.sApp.mDebugger.mIsRunning)
{
////
}
if ((mResultHoverWatch != null) && (mResultHoverWatch.mListView != null))
{
var listViewItems = (HoverWatch.HoverListViewItem)mResultHoverWatch.mListView.GetRoot().GetChildAtIndex(0);
if ((listViewItems.mWatchEntry.mIsPending) && (gApp.mDebugger.IsPaused(true)) && (!gApp.mDebugger.HasMessages()))
{
HandleResult(null);
}
}
if (!mDeferredChars.IsEmpty)
{
var c = mDeferredChars.PopFront();
KeyChar(c);
}
}
public void StartEntry()
{
mEditWidgetContent.AppendText("> ");
mEditWidgetContent.mData.mUndoManager.Clear();
mEditWidgetContent.mSelection = null;
mEditWidgetContent.mCursorTextPos = mEditWidgetContent.mData.mTextLength;
mEditWidgetContent.mIsReadOnly = false;
mEntryStartPos.mWasDeleted = false;
mEntryStartPos.mIndex = mEditWidgetContent.mData.mTextLength - 1;
}
public void RehupResult()
{
// Replace the old string with the new format
var listViewItem = mResultHoverWatch.mListView.GetRoot().GetChildAtIndex(0);
var subItem1 = listViewItem.GetSubItem(1);
var content = Content;
let prevSelection = content.mSelection;
defer { content.mSelection = prevSelection; }
int line;
int lineChar;
float overflowX;
content.GetLineCharAtCoord(mInfoButton.CenterX, mInfoButton.CenterY, out line, out lineChar, out overflowX);
int lineStart;
int lineEnd;
content.GetLinePosition(line, out lineStart, out lineEnd);
String replaceStr = scope String();
replaceStr.Append(" ");
replaceStr.Append(subItem1.Label);
content.mSelection = EditSelection(lineStart, lineEnd);
content.CursorTextPos = lineStart;
content.InsertAtCursor(replaceStr);
content.CursorTextPos = content.mData.mTextLength;
}
}
}

View file

@ -0,0 +1,241 @@
using Beefy.theme.dark;
using Beefy.widgets;
using Beefy.events;
using System;
using System.Collections.Generic;
using Beefy.gfx;
using IDE.Util;
using System.IO;
namespace IDE.ui
{
class InstalledProjectDialog : IDEDialog
{
class InstalledProject
{
public String mName ~ delete _;
public String mPath ~ delete _;
public VerSpecRecord mVersion;
}
protected IDEListView mProjectList;
EditWidget mEditWidget;
bool mFilterChanged;
List<InstalledProject> mInstalledProjectList = new .() ~ DeleteContainerAndItems!(_);
List<InstalledProject> mFilteredList = new .() ~ delete _;
public static Dictionary<String, int32> sMRU = new .() ~
{
for (let key in _.Keys)
delete key;
delete _;
};
public this()
{
mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable;
AddOkCancelButtons(new (evt) => { DoImport(); }, null, 0, 1);
//mApplyButton = AddButton("Apply", (evt) => { evt.mCloseDialog = false; ApplyChanges(); });
Title = "Import Installed Project";
mButtonBottomMargin = GS!(6);
mButtonRightMargin = GS!(6);
mProjectList = new .();
mProjectList.InitScrollbars(false, true);
mProjectList.mAllowMultiSelect = false;
mProjectList.mOnItemMouseDown.Add(new => ValueMouseDown);
ListViewColumn column = mProjectList.AddColumn(GS!(200), "Project");
column.mMinWidth = GS!(100);
column = mProjectList.AddColumn(GS!(200), "Path");
AddWidget(mProjectList);
mTabWidgets.Add(mProjectList);
mEditWidget = AddEdit("");
mEditWidget.mOnKeyDown.Add(new => EditKeyDownHandler);
mEditWidget.mOnContentChanged.Add(new (evt) => { mFilterChanged = true; });
FindProjects();
}
void FindProjects()
{
for (let registryEntry in gApp.mBeefConfig.mRegistry)
{
InstalledProject installedProject = new .();
installedProject.mName = new String(registryEntry.mProjName);
switch (registryEntry.mLocation.mVerSpec)
{
case .Path(let path):
installedProject.mPath = new String();
Path.GetAbsolutePath(path, registryEntry.mConfigFile.mConfigDir, installedProject.mPath);
installedProject.mPath.Append(Path.DirectorySeparatorChar);
installedProject.mPath.Append("BeefProj.toml");
default:
}
mInstalledProjectList.Add(installedProject);
}
}
void EditKeyDownHandler(KeyDownEvent evt)
{
switch (evt.mKeyCode)
{
case .Up,
.Down,
.PageUp,
.PageDown:
mProjectList.KeyDown(evt.mKeyCode, false);
default:
}
if (evt.mKeyFlags == .Ctrl)
{
switch (evt.mKeyCode)
{
case .Home,
.End:
mProjectList.KeyDown(evt.mKeyCode, false);
default:
}
}
}
public void ValueMouseDown(ListViewItem clickedItem, float x, float y, int32 btnNum, int32 btnCount)
{
DarkListViewItem item = (DarkListViewItem)clickedItem.GetSubItem(0);
mProjectList.GetRoot().SelectItemExclusively(item);
mProjectList.SetFocus();
if ((btnNum == 0) && (btnCount > 1))
{
DoImport();
}
}
void FilterFiles()
{
let root = mProjectList.GetRoot();
root.Clear();
String filterString = scope String();
mEditWidget.GetText(filterString);
filterString.Trim();
for (var installedProject in mInstalledProjectList)
{
if ((!filterString.IsEmpty) && (installedProject.mName.IndexOf(filterString, true) == -1))
continue;
var listViewItem = mProjectList.GetRoot().CreateChildItem();
listViewItem.Label = installedProject.mName;
var subListViewItem = listViewItem.CreateSubItem(1);
subListViewItem.Label = installedProject.mPath;
mFilteredList.Add(installedProject);
}
ListViewItem bestItem = null;
int32 bestPri = -1;
for (int32 childIdx = 0; childIdx < root.GetChildCount(); childIdx++)
{
var listViewItem = root.GetChildAtIndex(childIdx);
var projectSource = mFilteredList[childIdx];
int32 pri;
sMRU.TryGetValue(projectSource.mPath, out pri);
if (pri > bestPri)
{
bestItem = listViewItem;
bestPri = pri;
}
}
if (bestItem != null)
{
mProjectList.GetRoot().SelectItemExclusively(bestItem);
mProjectList.EnsureItemVisible(bestItem, true);
}
}
public void DoImport()
{
let root = mProjectList.GetRoot();
for (int idx < root.GetChildCount())
{
let listViewItem = root.GetChildAtIndex(idx);
if (!listViewItem.Selected)
continue;
let entry = mFilteredList[idx];
let verSpec = new VerSpecRecord();
verSpec.SetSemVer("*");
let project = gApp.mProjectPanel.ImportProject(entry.mPath, verSpec);
if (project == null)
{
delete verSpec;
return;
}
project.mLocked = true;
project.mLockedDefault = true;
}
Close();
}
public override void AddedToParent()
{
base.AddedToParent();
mEditWidget.SetFocus();
FilterFiles();
}
public override void ResizeComponents()
{
base.ResizeComponents();
//var font = DarkTheme.sDarkTheme.mSmallFont;
float insetSize = GS!(6);
mProjectList.Resize(insetSize, insetSize, mWidth - insetSize - insetSize, mHeight - GS!(66));
mEditWidget.Resize(insetSize, mProjectList.mY + mProjectList.mHeight + insetSize, mWidth - insetSize - insetSize, GS!(22));
}
public override void CalcSize()
{
mWidth = GS!(660);
mHeight = GS!(512);
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
IDEUtils.DrawOutline(g, mProjectList);
}
public override void Update()
{
base.Update();
if (mFilterChanged)
{
FilterFiles();
mFilterChanged = false;
}
}
}
}

446
IDE/src/ui/LaunchDialog.bf Normal file
View file

@ -0,0 +1,446 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.gfx;
using Beefy.theme.dark;
using Beefy.widgets;
using System.IO;
using System.Diagnostics;
namespace IDE.ui
{
public class LaunchDialog : IDEDialog
{
const String cBrowseCmd = "< Browse ... >";
const String cCurProjectCmd = "< Current Debug Setting >";
PathComboBox mTargetCombo;
DarkComboBox mArgumentsCombo;
DarkComboBox mWorkingDirCombo;
DarkComboBox mEnvironmentCombo;
DarkCheckBox mDebugCheckbox;
DarkCheckBox mPausedCheckbox;
DarkCheckBox mProfileCheckbox;
bool mIgnoreContentChanged;
public this()
{
mSettingHistoryManager = gApp.mLaunchHistoryManager;
mTitle = new .("Launch Executable");
mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable;
AddOkCancelButtons(new (evt) => { evt.mCloseDialog = false; Launch(); }, null, 0, 1);
mButtonBottomMargin = GS!(6);
mButtonRightMargin = GS!(6);
mTargetCombo = new PathComboBox();
mTargetCombo.MakeEditable(new PathEditWidget());
mTargetCombo.Label = "";
mTargetCombo.mPopulateMenuAction.Add(new => PopulateTargetMenu);
AddWidget(mTargetCombo);
AddEdit(mTargetCombo.mEditWidget);
mArgumentsCombo = new DarkComboBox();
mArgumentsCombo.MakeEditable();
mArgumentsCombo.Label = "";
mArgumentsCombo.mPopulateMenuAction.Add(new => PopulateArgumentsMenu);
AddWidget(mArgumentsCombo);
AddEdit(mArgumentsCombo.mEditWidget);
mWorkingDirCombo = new PathComboBox();
mWorkingDirCombo.MakeEditable(new PathEditWidget());
mWorkingDirCombo.Label = "";
mWorkingDirCombo.mPopulateMenuAction.Add(new => PopulateWorkingDirMenu);
AddWidget(mWorkingDirCombo);
AddEdit(mWorkingDirCombo.mEditWidget);
mEnvironmentCombo = new DarkComboBox();
mEnvironmentCombo.MakeEditable();
mEnvironmentCombo.Label = "";
mEnvironmentCombo.mPopulateMenuAction.Add(new => PopulateEnvironmentMenu);
AddWidget(mEnvironmentCombo);
AddEdit(mEnvironmentCombo.mEditWidget);
mDebugCheckbox = new DarkCheckBox();
mDebugCheckbox.Label = "&Debug";
mDebugCheckbox.Checked = true;
AddDialogComponent(mDebugCheckbox);
mPausedCheckbox = new DarkCheckBox();
mPausedCheckbox.Label = "&Start Paused";
mPausedCheckbox.Checked = false;
AddDialogComponent(mPausedCheckbox);
mProfileCheckbox = new DarkCheckBox();
mProfileCheckbox.Label = "P&rofile";
mProfileCheckbox.Checked = false;
AddDialogComponent(mProfileCheckbox);
//mPrevButton = new DarkButton();
//mPrevButton.Label = "< Prev";
CreatePrevNextButtons();
}
protected override void UseProps(PropertyBag propBag)
{
mTargetCombo.Label = propBag.Get<String>("Target") ?? "";
mArgumentsCombo.Label = propBag.Get<String>("Arguments") ?? "";
mWorkingDirCombo.Label = propBag.Get<String>("WorkingDir") ?? "";
mEnvironmentCombo.Label = propBag.Get<String>("EnvVars") ?? "";
mDebugCheckbox.Checked = propBag.Get<bool>("Debug", true);
mPausedCheckbox.Checked = propBag.Get<bool>("StartPaused");
mProfileCheckbox.Checked = propBag.Get<bool>("Profile");
}
void SaveProps()
{
PropertyBag propBag = new PropertyBag();
propBag.Add("Target", mTargetCombo.Label);
propBag.Add("Arguments", mArgumentsCombo.Label);
propBag.Add("WorkingDir", mWorkingDirCombo.Label);
propBag.Add("EnvVars", mEnvironmentCombo.Label);
propBag.Add("Debug", mDebugCheckbox.Checked);
propBag.Add("StartPaused", mPausedCheckbox.Checked);
propBag.Add("Profile", mProfileCheckbox.Checked);
mSettingHistoryManager.Add(propBag);
}
bool GetStartupOption(delegate String (Project.Options options) dlg, String outString)
{
if (gApp.mWorkspace.mStartupProject != null)
{
let options = gApp.GetCurProjectOptions(gApp.mWorkspace.mStartupProject);
let workspaceOptions = gApp.GetCurWorkspaceOptions();
var inStr = dlg(options);
if (inStr == null)
return false;
gApp.ResolveConfigString(workspaceOptions, gApp.mWorkspace.mStartupProject, options, inStr, "", outString);
return true;
}
return false;
}
void DoBrowse()
{
#if !CLI
String str = scope String();
GetStartupOption(scope (options) => options.mDebugOptions.mCommand, str);
String dir = scope String();
Path.GetDirectoryPath(str, dir);
IDEUtils.FixFilePath(dir);
var fileDialog = scope System.IO.OpenFileDialog();
fileDialog.ShowReadOnly = false;
fileDialog.Title = "Select Executable";
fileDialog.Multiselect = true;
if (!dir.IsEmpty)
fileDialog.InitialDirectory = dir;
fileDialog.ValidateNames = true;
fileDialog.DefaultExt = ".exe";
fileDialog.SetFilter("Executables (*.exe)|*.exe|All files (*.*)|*.*");
mWidgetWindow.PreModalChild();
if (fileDialog.ShowDialog(gApp.GetActiveWindow()) case .Ok)
{
var fileNames = fileDialog.FileNames;
if (!fileNames.IsEmpty)
mTargetCombo.Label = fileNames[0];
}
#endif
}
void PopulateTargetMenu(Menu menu)
{
var item = menu.AddItem(cBrowseCmd);
item.mOnMenuItemSelected.Add(new (dlg) =>
{
DoBrowse();
});
item = menu.AddItem(cCurProjectCmd);
item.mOnMenuItemSelected.Add(new (dlg) =>
{
mIgnoreContentChanged = true;
String str = scope String();
GetStartupOption(scope (options) => options.mDebugOptions.mCommand, str);
mTargetCombo.Label = str;
mIgnoreContentChanged = false;
});
}
void PopulateArgumentsMenu(Menu menu)
{
var item = menu.AddItem(cCurProjectCmd);
item.mOnMenuItemSelected.Add(new (dlg) =>
{
mIgnoreContentChanged = true;
String str = scope String();
GetStartupOption(scope (options) => options.mDebugOptions.mCommandArguments, str);
mArgumentsCombo.Label = str;
mIgnoreContentChanged = false;
});
}
void PopulateWorkingDirMenu(Menu menu)
{
var item = menu.AddItem(cCurProjectCmd);
item.mOnMenuItemSelected.Add(new (dlg) =>
{
mIgnoreContentChanged = true;
String str = scope String();
GetStartupOption(scope (options) => options.mDebugOptions.mWorkingDirectory, str);
mWorkingDirCombo.Label = str;
mIgnoreContentChanged = false;
});
}
void PopulateEnvironmentMenu(Menu menu)
{
var item = menu.AddItem(cCurProjectCmd);
item.mOnMenuItemSelected.Add(new (dlg) =>
{
mIgnoreContentChanged = true;
String str = scope String();
for (int i = 0; true; i++)
{
var curStr = scope String();
if (!GetStartupOption(scope (options) =>
{
if (i < options.mDebugOptions.mEnvironmentVars.Count)
return options.mDebugOptions.mEnvironmentVars[i];
return null;
}, curStr))
break;
if (!str.IsEmpty)
str.Append(";");
str.Append(curStr);
}
mEnvironmentCombo.Label = str;
mIgnoreContentChanged = false;
});
}
public static void DoLaunch(LaunchDialog dialog, String targetPath, String arguments, String workingDir, String envVarStr, bool startPaused, bool debug)
{
var workingDir;
if (!File.Exists(targetPath))
{
dialog?.mTargetCombo.SetFocus();
gApp.Fail(scope String()..AppendF("Unable to locate target file '{0}'", targetPath));
return;
}
if (workingDir.IsWhiteSpace)
{
workingDir = scope:: .(@workingDir);
Path.GetDirectoryPath(targetPath, workingDir);
}
if (workingDir.EndsWith('\\') || workingDir.EndsWith('/'))
workingDir.RemoveFromEnd(1);
if (!Directory.Exists(workingDir))
{
dialog?.mWorkingDirCombo.SetFocus();
gApp.Fail(scope String()..AppendF("Unable to locate working directory '{0}'", workingDir));
return;
}
if (gApp.mDebugger.mIsRunning)
{
gApp.Fail("An executable is already being debugged");
return;
}
gApp.mProfilePanel.Clear();
gApp.mDebugger.ClearInvalidBreakpoints();
gApp.mExecutionPaused = false;
gApp.mTargetDidInitBreak = false;
gApp.mTargetHadFirstBreak = false;
if (!debug)
{
ProcessStartInfo procInfo = scope ProcessStartInfo();
procInfo.UseShellExecute = false;
procInfo.SetWorkingDirectory(workingDir);
procInfo.SetArguments(arguments);
for (var envVar in envVarStr.Split(';'))
{
envVar.Trim();
if (envVar.IsEmpty)
continue;
int eqPos = envVar.IndexOf('=', 1);
if (eqPos == -1)
{
gApp.OutputErrorLine("Invalid environment variable: {0}", envVar);
}
else
{
procInfo.AddEnvironmentVariable(StringView(envVar, 0, eqPos), StringView(envVar, eqPos + 1));
}
}
procInfo.SetFileName(targetPath);
var spawnedProcess = scope SpawnedProcess();
if (spawnedProcess.Start(procInfo) case .Err)
{
gApp.Fail(scope String()..AppendF("Unable to start executable: {0}", targetPath));
}
return;
}
if (startPaused)
{
gApp.mTargetDidInitBreak = true;
gApp.mTargetHadFirstBreak = true;
}
var envVars = scope Dictionary<String, String>();
defer { for (var kv in envVars) { delete kv.key; delete kv.value; } }
Environment.GetEnvironmentVariables(envVars);
for (var envVar in envVarStr.Split(';'))
{
envVar.Trim();
if (envVar.IsEmpty)
continue;
int eqPos = envVar.IndexOf('=', 1);
if (eqPos == -1)
{
gApp.OutputErrorLine("Invalid environment variable: {0}", envVar);
}
else
{
Environment.SetEnvironmentVariable(envVars, StringView(envVar, 0, eqPos), StringView(envVar, eqPos + 1));
}
}
var envBlock = scope List<char8>();
Environment.EncodeEnvironmentVariables(envVars, envBlock);
if (!gApp.mDebugger.OpenFile(targetPath, arguments, workingDir, envBlock, false))
{
gApp.Fail(scope String()..AppendF("Unable to open executable for debugging: {0}", targetPath));
return;
}
gApp.[Friend]CheckDebugVisualizers();
gApp.mDebugger.mIsRunning = true;
gApp.mDebugger.RehupBreakpoints(true);
gApp.mDebugger.Run();
}
void Launch()
{
var targetPath = scope String();
targetPath.Append(mTargetCombo.Label);
IDEUtils.FixFilePath(targetPath);
String workingDir = scope String();
//
{
String relWorkingDir = scope String();
relWorkingDir.Append(mWorkingDirCombo.Label);
if (!workingDir.IsWhiteSpace)
{
Path.GetAbsolutePath(targetPath, relWorkingDir, workingDir);
}
}
String envVarStr = scope String();
envVarStr.Append(mEnvironmentCombo.Label);
String arguments = scope String();
arguments.Append(mArgumentsCombo.Label);
DoLaunch(this, targetPath, arguments, workingDir, envVarStr, mPausedCheckbox.Checked, mDebugCheckbox.Checked);
SaveProps();
Close();
}
public override void ResizeComponents()
{
base.ResizeComponents();
float curY = GS!(30);
mTargetCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
curY += GS!(42);
mArgumentsCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
curY += GS!(42);
mWorkingDirCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
curY += GS!(42);
mEnvironmentCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
curY += GS!(28);
mDebugCheckbox.Resize(GS!(6), curY, mProfileCheckbox.CalcWidth(), GS!(22));
curY += GS!(22);
mPausedCheckbox.Resize(GS!(6), curY, mPausedCheckbox.CalcWidth(), GS!(22));
curY += GS!(22);
mProfileCheckbox.Resize(GS!(6), curY, mProfileCheckbox.CalcWidth(), GS!(22));
}
public override void CalcSize()
{
mWidth = GS!(400);
mHeight = GS!(260);
}
public override void AddedToParent()
{
base.AddedToParent();
RehupMinSize();
}
void RehupMinSize()
{
mWidgetWindow.SetMinimumSize(GS!(280), GS!(280), true);
}
public override void RehupScale(float oldScale, float newScale)
{
base.RehupScale(oldScale, newScale);
RehupMinSize();
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
public override void Draw(Graphics g)
{
base.Draw(g);
g.DrawString("Target Path:", GS!(6), mTargetCombo.mY - GS!(18));
g.DrawString("Arguments:", GS!(6), mArgumentsCombo.mY - GS!(18));
g.DrawString("Working Directory:", GS!(6), mWorkingDirCombo.mY - GS!(18));
g.DrawString("Environment Variables:", GS!(6), mEnvironmentCombo.mY - GS!(18));
}
public override void Update()
{
base.Update();
}
}
}

74
IDE/src/ui/LeakWidget.bf Normal file
View file

@ -0,0 +1,74 @@
using Beefy.widgets;
using Beefy.gfx;
using Beefy.geom;
using Beefy.theme.dark;
using System;
using System.Collections.Generic;
namespace IDE.ui
{
class LeakWidget : Widget
{
public String mExpr ~ delete _;
public List<String> mStackAddrs = new List<String>() ~ DeleteContainerAndItems!(_);
public OutputPanel mOutputPanel ~
{
if (mCreatedTextPanel)
delete _;
};
bool mCreatedTextPanel;
public this(OutputPanel panel = null)
{
mOutputPanel = panel;
}
public override void Draw(Graphics g)
{
g.Draw(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.MoreInfo));
}
public override void MouseEnter()
{
base.MouseEnter();
/*if (mOutputPanel == null)
{
var emptyTextPanel = new EmptyTextPanel();
emptyTextPanel.mHoverWatchRect = Rect(0, 0, mWidth, mHeight);
mOutputPanel = emptyTextPanel;
AddWidget(mOutputPanel);
//mCreatedTextPanel = true;
}*/
int line;
int column;
mOutputPanel.EditWidget.Content.GetLineAndColumnAtCoord(mX + mWidth / 2, mY + mHeight / 2, out line, out column);
mOutputPanel.mHoverWatchLine = (int32)line;
// So we can default our evaluation to the general global Beef state
/*let prevIdx = gApp.mDebugger.mSelectedCallStackIdx;
defer { gApp.mDebugger.mSelectedCallStackIdx = prevIdx; };
gApp.mDebugger.mSelectedCallStackIdx = -1; */
if (mOutputPanel.mHoverWatch != null)
mOutputPanel.mHoverWatch.Close();
String evalStr = scope String();
evalStr.Append(mExpr);
//evalStr.AppendF("{0}", mAddr);
var hoverWatch = new HoverWatch();
hoverWatch.mLanguage = .Beef;
hoverWatch.mDeselectCallStackIdx = true;
hoverWatch.mAllowLiterals = true;
hoverWatch.mAllowSideEffects = true;
//hoverWatch.mOrigEvalString.Set(evalStr);
//hoverWatch.SetListView(mImmediateWidget.mResultHoverWatch.mListView);
//hoverWatch.Show(mTextPanel, mX + 2, mY + 3, evalStr);
hoverWatch.mOpenMousePos = DarkTooltipManager.sLastRelMousePos;
hoverWatch.Show(mOutputPanel, mX, mY, evalStr);
mOutputPanel.mHoverWatch = hoverWatch;
}
}
}

76
IDE/src/ui/LocatorAnim.bf Normal file
View file

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.gfx;
using Beefy.widgets;
using Beefy.theme.dark;
namespace IDE.ui
{
public enum LocatorType
{
None,
Smart,
Always
}
public class LocatorAnim : Widget
{
float mPct;
public override void Draw(Graphics g)
{
base.Draw(g);
int32 circleCount = 2;
for (int32 i = 0; i < circleCount; i++)
{
float sepPct = 0.3f;
float maxSep = (circleCount - 2) * sepPct;
float pct = (mPct - maxSep + (i * 0.3f)) / (1.0f - maxSep);
if ((pct < 0.0f) || (pct > 1.0f))
continue;
float scale = (float)Math.Sin(pct * Math.PI_f / 2) * 0.5f;
float alpha = Math.Min(0.3f, (1.0f - (float)Math.Sin(pct * Math.PI_f / 2)) * 1.0f);
using (g.PushColor(Color.Get(alpha)))
{
using (g.PushScale(scale, scale, GS!(32), GS!(32)))
g.Draw(IDEApp.sApp.mCircleImage);
}
}
}
public override void Update()
{
base.Update();
mPct += 0.03f;
if (mPct >= 1.0f)
{
RemoveSelf();
//DeferDelete();
gApp.DeferDelete(this);
}
MarkDirty();
}
public static void Show(Widget refWidget, float x, float y)
{
if (!gApp.mSettings.mEditorSettings.mShowLocatorAnim)
return;
float xOfs = GS!(-32.0f);
float yOfs = GS!(-32.0f);
LocatorAnim anim = new LocatorAnim();
anim.mX = x + xOfs;
anim.mY = y + yOfs;
refWidget.AddWidget(anim);
}
}
}

48
IDE/src/ui/MainFrame.bf Normal file
View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.gfx;
using Beefy.widgets;
using Beefy.theme;
using Beefy.theme.dark;
namespace IDE.ui
{
public class MainFrame : Widget
{
public StatusBar mStatusBar;
public DarkDockingFrame mDockingFrame;
public this()
{
mStatusBar = new StatusBar();
AddWidget(mStatusBar);
mDockingFrame = (DarkDockingFrame)ThemeFactory.mDefault.CreateDockingFrame();
AddWidget(mDockingFrame);
}
public void Reset()
{
mDockingFrame.RemoveSelf();
gApp.DeferDelete(mDockingFrame);
mDockingFrame = (DarkDockingFrame)ThemeFactory.mDefault.CreateDockingFrame();
AddWidget(mDockingFrame);
RehupSize();
}
public ~this()
{
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
int32 statusHeight = GS!(20);
mDockingFrame.Resize(0, 0, width, height - statusHeight);
mStatusBar.Resize(0, mHeight - statusHeight, width, statusHeight);
}
}
}

1227
IDE/src/ui/MemoryPanel.bf Normal file

File diff suppressed because it is too large Load diff

178
IDE/src/ui/ModulePanel.bf Normal file
View file

@ -0,0 +1,178 @@
using Beefy.theme.dark;
using System;
using Beefy.widgets;
using Beefy.theme;
using System.IO;
using Beefy.utils;
namespace IDE.ui
{
class ModulePanel : Panel
{
public IDEListView mListView;
bool mModulesDirty = true;
public this()
{
mListView = new IDEListView();
mListView.InitScrollbars(true, true);
mListView.mHorzScrollbar.mPageSize = GS!(100);
mListView.mHorzScrollbar.mContentSize = GS!(500);
mListView.mVertScrollbar.mPageSize = GS!(100);
mListView.mVertScrollbar.mContentSize = GS!(500);
mListView.mAutoFocus = true;
mListView.mOnLostFocus.Add(new (evt) =>
{
if (!mShowingRightClickMenu)
mListView.GetRoot().SelectItemExclusively(null);
});
mListView.UpdateScrollbars();
AddWidget(mListView);
ListViewColumn column = mListView.AddColumn(GS!(100), "Name");
column.mMinWidth = GS!(130);
column = mListView.AddColumn(GS!(200), "Path");
column = mListView.AddColumn(GS!(200), "Debug Info File");
column = mListView.AddColumn(GS!(120), "Version");
column = mListView.AddColumn(GS!(200), "Address");
column = mListView.AddColumn(GS!(100), "Size");
column = mListView.AddColumn(GS!(120), "Timestamp");
mListView.mOnItemMouseDown.Add(new => ListViewItemMouseDown);
mListView.mOnItemMouseClicked.Add(new => ListViewItemMouseClicked);
mListView.mOnKeyDown.Add(new => ListViewKeyDown_ShowMenu);
}
public override void Serialize(StructuredData data)
{
base.Serialize(data);
data.Add("Type", "ModulePanel");
}
public override void FocusForKeyboard()
{
// Update to allow for populating of list if necessary
Update();
mListView.SetFocus();
if ((mListView.GetRoot().FindFocusedItem() == null) && (mListView.GetRoot().GetChildCount() > 0))
{
mListView.GetRoot().SelectItemExclusively(mListView.GetRoot().GetChildAtIndex(0));
}
}
public void ModulesChanged()
{
mModulesDirty = true;
}
protected override void ShowRightClickMenu(Widget relWidget, float x, float y)
{
base.ShowRightClickMenu(relWidget, x, y);
#if !CLI
var root = relWidget as ListViewItem;
var listView = root.mListView;
if (listView.GetRoot().FindFirstSelectedItem() != null)
{
Menu menu = new Menu();
Menu anItem;
anItem = menu.AddItem("Load Symbols...");
anItem.mOnMenuItemSelected.Add(new (item) =>
{
listView.GetRoot().WithSelectedItems(scope (item) =>
{
var pathItem = item.GetSubItem(1);
String dir = scope String();
Path.GetDirectoryPath(pathItem.Label, dir);
IDEUtils.FixFilePath(dir);
var fileDialog = scope System.IO.OpenFileDialog();
fileDialog.ShowReadOnly = false;
fileDialog.Title = "Select Debug Info File";
fileDialog.Multiselect = false;
if (!dir.IsEmpty)
fileDialog.InitialDirectory = dir;
fileDialog.ValidateNames = true;
fileDialog.DefaultExt = ".exe";
fileDialog.SetFilter("PDB Debug Unfo (*.pdb)|*.pdb|All files (*.*)|*.*");
mWidgetWindow.PreModalChild();
if (fileDialog.ShowDialog(gApp.GetActiveWindow()).GetValueOrDefault() == .OK)
{
var fileNames = fileDialog.FileNames;
if (gApp.mDebugger.mIsRunning)
{
gApp.mDebugger.LoadDebugInfoForModule(scope String(pathItem.Label), fileNames[0]);
}
}
});
});
MenuWidget menuWidget = ThemeFactory.mDefault.CreateMenuWidget(menu);
menuWidget.Init(relWidget, x, y);
}
#endif
}
void UpdateModules()
{
int idx = 0;
if (gApp.mDebugger.mIsRunning)
{
var modulesInfoStr = scope String();
gApp.mDebugger.GetModulesInfo(modulesInfoStr);
for (let moduleInfoStr in modulesInfoStr.Split('\n'))
{
if (moduleInfoStr.IsEmpty)
continue;
if (idx < mListView.GetRoot().GetChildCount())
{
let lvItem = mListView.GetRoot().GetChildAtIndex(idx);
int subIdx = 0;
for (let moduleStr in moduleInfoStr.Split('\t'))
{
let subLVItem = (subIdx == 0) ? lvItem : lvItem.GetSubItem(subIdx);
subLVItem.Label = moduleStr;
subIdx++;
}
}
else
{
let lvItem = mListView.GetRoot().CreateChildItem();
int subIdx = 0;
for (let moduleStr in moduleInfoStr.Split('\t'))
{
let subLVItem = (subIdx == 0) ? lvItem : lvItem.CreateSubItem(subIdx);
subLVItem.Label = moduleStr;
subIdx++;
}
}
++idx;
}
}
while (idx < mListView.GetRoot().GetChildCount())
mListView.GetRoot().RemoveChildItemAt(idx);
}
public override void Update()
{
base.Update();
if (mModulesDirty)
{
UpdateModules();
mModulesDirty = false;
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
mListView.Resize(0, 0, width, height);
mListView.ScrollPositionChanged();
}
}
}

View file

@ -0,0 +1,136 @@
using Beefy.widgets;
using System;
using System.Collections.Generic;
using Beefy.theme.dark;
using Beefy.gfx;
using Beefy.events;
namespace IDE.ui
{
class MultiSelectDialog : IDEDialog
{
class ListView : IDEListView
{
public override void KeyDown(KeyCode keyCode, bool isRepeat)
{
base.KeyDown(keyCode, isRepeat);
var multiSelectDialog = (MultiSelectDialog)mParent;
if (keyCode == .Space)
{
var root = GetRoot();
int childCount = root.GetChildCount();
for (int i < childCount)
{
var listViewItem = root.GetChildAtIndex(i);
if (listViewItem.Selected)
{
var entry = multiSelectDialog.[Friend]mEntries[i];
entry.mCheckbox.Checked = !entry.mCheckbox.Checked;
}
}
}
}
}
ListView mListView;
public class Entry
{
public String mName ~ delete _;
public CheckBox mCheckbox;
public bool mInitialChecked;
}
public List<Entry> mEntries = new .() ~ DeleteContainerAndItems!(_);
Dictionary<ListViewItem, Entry> mEntryMap = new .() ~ delete _;
public this()
{
mTitle = new String("Configuration Manager");
mWindowFlags |= .Resizable;
mListView = new ListView();
mListView.InitScrollbars(false, true);
mListView.mVertScrollbar.mPageSize = GS!(100);
mListView.mVertScrollbar.mContentSize = GS!(500);
mListView.UpdateScrollbars();
mListView.AddColumn(100, "Name");
mListView.mLabelX = GS!(32);
mTabWidgets.Add(mListView);
AddWidget(mListView);
}
public void Add(String name, bool isChecked = false)
{
var entry = new Entry();
entry.mName = new String(name);
entry.mInitialChecked = isChecked;
mEntries.Add(entry);
}
public void FinishInit()
{
mEntries.Sort(scope (lhs, rhs) => String.Compare(lhs.mName, rhs.mName, true));
for (let entry in mEntries)
{
let listViewItem = mListView.GetRoot().CreateChildItem();
listViewItem.Label = entry.mName;
listViewItem.mOnMouseDown.Add(new => ValueClicked);
entry.mCheckbox = new DarkCheckBox();
entry.mCheckbox.Checked = entry.mInitialChecked;
entry.mCheckbox.Resize(GS!(8), GS!(1), GS!(20), GS!(20));
listViewItem.AddWidget(entry.mCheckbox);
if (@entry.Index == 0)
listViewItem.Focused = true;
mEntryMap[listViewItem] = entry;
}
}
public override void AddedToParent()
{
mListView.SetFocus();
}
public override void CalcSize()
{
mWidth = GS!(280);
mHeight = GS!(190);
}
public override void ResizeComponents()
{
base.ResizeComponents();
mListView.Resize(GS!(6), GS!(6), mWidth - GS!(12), mHeight - GS!(48));
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
IDEUtils.DrawOutline(g, mListView, 0, 1);
}
public void ValueClicked(MouseEvent theEvent)
{
let clickedItem = (DarkListViewItem)theEvent.mSender;
mListView.SetFocus();
if (theEvent.mBtn == 1)
{
if (!clickedItem.Selected)
mListView.GetRoot().SelectItem(clickedItem, true);
}
else
{
mListView.GetRoot().SelectItem(clickedItem, true);
}
}
}
}

257
IDE/src/ui/NavigationBar.bf Normal file
View file

@ -0,0 +1,257 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy.events;
using Beefy.gfx;
using Beefy.theme.dark;
using Beefy.widgets;
using IDE.Compiler;
using System.Diagnostics;
namespace IDE.ui
{
class NavigationBar : DarkComboBox
{
enum EntryType
{
Unknown,
Method,
Property,
Class,
Enum,
Struct,
TypeAlias
}
class Entry
{
public String mText ~ delete _;
public EntryType mEntryType;
public int32 mLine;
public int32 mLineChar;
}
public static Dictionary<String, int32> sMRU = new Dictionary<String, int32>() ~ delete _;
public static int32 sCurrentMRUIndex = 1;
SourceViewPanel mSourceViewPanel;
List<Entry> mEntries = new List<Entry>() ~ DeleteContainerAndItems!(_);
List<Entry> mShownEntries = new List<Entry>() ~ delete _;
String mFilterString ~ delete _;
String mCurLocation = new String() ~ delete _;
bool mIgnoreChange = false;
public this(SourceViewPanel sourceViewPanel)
{
mSourceViewPanel = sourceViewPanel;
mLabelAlign = FontAlign.Left;
Label = "";
mLabelX = GS!(16);
mPopulateMenuAction.Add(new => PopulateNavigationBar);
MakeEditable();
mEditWidget.mOnContentChanged.Add(new => NavigationBarChanged);
mEditWidget.mOnKeyDown.Add(new => EditKeyDownHandler);
mEditWidget.mEditWidgetContent.mWantsUndo = false;
mFocusDropdown = false;
}
public ~this()
{
}
static ~this()
{
for (var key in sMRU.Keys)
delete key;
}
public void SetLocation(String location)
{
if (mCurMenuWidget == null)
{
mIgnoreChange = true;
mEditWidget.SetText(location);
// SetText can attempt to scroll to the right to make the cursor position visible. Just scroll back to the start.
mEditWidget.HorzScrollTo(0);
mIgnoreChange = false;
}
}
void EditKeyDownHandler(KeyDownEvent evt)
{
if (evt.mKeyCode == KeyCode.Escape)
mSourceViewPanel.FocusEdit();
}
void GetEntries()
{
DeleteAndClearItems!(mEntries);
ResolveParams resolveParams = scope ResolveParams();
mSourceViewPanel.Classify(ResolveType.GetNavigationData, resolveParams);
if (resolveParams.mNavigationData != null)
{
var autocompleteLines = scope List<StringView>(resolveParams.mNavigationData.Split('\n'));
autocompleteLines.Sort(scope (a, b) => StringView.Compare(a, b, true));
for (var autocompleteLineView in autocompleteLines)
{
if (autocompleteLineView.Length == 0)
continue;
Entry entry = new Entry();
int idx = 0;
for (var lineData in autocompleteLineView.Split('\t'))
{
switch (idx)
{
case 0: entry.mText = new String(lineData);
case 1:
switch(lineData)
{
case "method": entry.mEntryType = .Method;
case "property": entry.mEntryType = .Property;
case "class": entry.mEntryType = .Class;
case "enum": entry.mEntryType = .Enum;
case "struct": entry.mEntryType = .Struct;
case "typealias": entry.mEntryType = .TypeAlias;
default:
}
case 2: entry.mLine = int32.Parse(lineData);
case 3: entry.mLineChar = int32.Parse(lineData);
}
++idx;
}
mEntries.Add(entry);
}
}
}
private void PopulateNavigationBar(Menu menu)
{
List<StringView> findStrs = null;
if (mFilterString != null)
findStrs = scope:: List<StringView>(mFilterString.Split(' '));
EntryLoop: for (int32 entryIdx = 0; entryIdx < mEntries.Count; entryIdx++)
{
var entry = mEntries[entryIdx];
if (findStrs != null)
{
for (let findStr in findStrs)
{
if (entry.mText.IndexOf(findStr, true) == -1)
continue EntryLoop;
}
}
mShownEntries.Add(entry);
var menuItem = menu.AddItem(entry.mText);
switch (entry.mEntryType)
{
case .Method: menuItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Method);
case .Property: menuItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Property);
case .Class: menuItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Type_Class);
case .Enum: menuItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Type_ValueType);
case .Struct: menuItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.Type_ValueType);
case .TypeAlias: menuItem.mIconImage = DarkTheme.sDarkTheme.GetImage(.MemoryArrowSingle);
default:
}
menuItem.mOnMenuItemSelected.Add(new (evt) => ShowEntry(entryIdx, entry));
}
}
void ShowEntry(int32 entryIdx, Entry entry)
{
//sMRU[entry.mText] = sCurrentMRUIndex++;
String* keyPtr;
int32* valPtr;
if (sMRU.TryAdd(entry.mText, out keyPtr, out valPtr))
*keyPtr = new String(entry.mText);
*valPtr = sCurrentMRUIndex++;
mSourceViewPanel.ShowFileLocation(-1, entry.mLine, entry.mLineChar, LocatorType.Always);
}
private void NavigationBarChanged(EditEvent theEvent)
{
if (mIgnoreChange)
return;
var editWidget = (EditWidget)theEvent.mSender;
var searchText = scope String();
editWidget.GetText(searchText);
searchText.Trim();
mFilterString = searchText;
ShowDropdown();
mFilterString = null;
}
bool mShowingDropdown;
public override MenuWidget ShowDropdown()
{
if (mShowingDropdown)
return null;
mShowingDropdown = true;
defer(scope) { mShowingDropdown = false; }
/*var stopWatch = scope Stopwatch();
stopWatch.Start();*/
//Profiler.StartSampling();
if (!mEditWidget.mHasFocus)
SetFocus();
if (mCurMenuWidget == null)
GetEntries();
if (mFilterString == null)
mEditWidget.Content.SelectAll();
mShownEntries.Clear();
base.ShowDropdown();
int32 bestItem = -1;
int32 bestPri = -1;
var menuWidget = (DarkMenuWidget)mCurMenuWidget;
for (int32 itemIdx = 0; itemIdx < menuWidget.mItemWidgets.Count; itemIdx++)
{
var menuItemWidget = (DarkMenuItem)menuWidget.mItemWidgets[itemIdx];
int32 pri;
sMRU.TryGetValue(menuItemWidget.mMenuItem.mLabel, out pri);
if (pri > bestPri)
{
bestItem = itemIdx;
bestPri = pri;
}
}
if (bestItem != -1)
{
mCurMenuWidget.mOnSelectionChanged.Add(new => SelectionChanged);
mCurMenuWidget.SetSelection(bestItem);
}
//Profiler.StopSampling();
//stopWatch.Stop();
//Debug.WriteLine("Time: {0}", stopWatch.ElapsedMilliseconds);
return menuWidget;
}
void SelectionChanged(int selIdx)
{
if (mEditWidget.mEditWidgetContent.HasSelection())
mEditWidget.SetText("");
}
public override void MenuClosed()
{
mSourceViewPanel.FocusEdit();
}
}
}

View file

@ -0,0 +1,181 @@
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;
namespace IDE.ui
{
public class NewBreakpointDialog : IDEDialog
{
public enum BreakpointKind
{
Memory,
Symbol
}
EditWidget mAddressEdit;
String mExpr ~ delete _;
public bool mIsPending;
BreakpointKind mBreakpointKind;
public this(BreakpointKind breakpointKind)
{
mBreakpointKind = breakpointKind;
if (mBreakpointKind == .Memory)
Title = "New Memory Breakpoint";
else
Title = "New Symbol Breakpoint";
}
public override void CalcSize()
{
mWidth = GS!(320);
mHeight = GS!(100);
}
void DoCreateMemoryBreakpoint(int addr, int byteCount, String addrType, bool showOptions)
{
if (addr == 0)
return;
var breakpoint = IDEApp.sApp.mDebugger.CreateMemoryBreakpoint(mExpr, addr, byteCount, addrType);
if (!breakpoint.IsBound())
IDEApp.sApp.mBreakpointPanel.ShowMemoryBreakpointError();
Close();
gApp.RefreshWatches();
if (showOptions)
{
var widgetWindow = mWidgetWindow.mParent as WidgetWindow;
ConditionDialog dialog = new ConditionDialog();
dialog.Init(breakpoint);
dialog.PopupWindow(widgetWindow);
}
}
public bool CreateBreakpoint(bool showOptions)
{
if (var sourceEditWidgetContent = mAddressEdit.Content as SourceEditWidgetContent)
{
if (sourceEditWidgetContent.mAutoComplete != null)
sourceEditWidgetContent.KeyChar('\t');
}
delete mExpr;
mExpr = new String();
mAddressEdit.GetText(mExpr);
mExpr.Trim();
if (mBreakpointKind == .Memory)
{
int addr = 0;
int32 byteCount = 0;
String addrType = scope String();
switch (gApp.mBreakpointPanel.TryCreateMemoryBreakpoint(mExpr, out addr, out byteCount, addrType,
new (addr, byteCount, addrType) => { DoCreateMemoryBreakpoint(addr, byteCount, addrType, showOptions); }))
{
case .Pending:
SetPending(true);
return false;
case .Failure:
return false;
case .Success:
}
DoCreateMemoryBreakpoint(addr, byteCount, addrType, showOptions);
}
else
{
gApp.mDebugger.CreateSymbolBreakpoint(mExpr);
Close();
}
return true;
}
public void Init()
{
mDefaultButton = AddButton("Create", new (evt) => { CreateBreakpoint(false); evt.mCloseDialog = false; });
AddButton("Create...", new (evt) => { CreateBreakpoint(true); evt.mCloseDialog = false; });
mEscButton = AddButton("Cancel", new (evt) => Close());
//mNameEdit = AddEdit("NewProject");
//mDirectoryEdit = AddEdit(IDEApp.sApp.mWorkspace.mDir);
let addressEdit = new ExpressionEditWidget();
if (mBreakpointKind == .Memory)
addressEdit.mIsAddress = true;
else
addressEdit.mIsSymbol = true;
mAddressEdit = addressEdit;
mAddressEdit = addressEdit;
AddWidget(mAddressEdit);
mTabWidgets.Add(mAddressEdit);
//mAddressEdit.
mAddressEdit.mOnSubmit.Add(new => EditSubmitHandler);
mAddressEdit.mOnCancel.Add(new => EditCancelHandler);
}
public override void PopupWindow(WidgetWindow parentWindow, float offsetX = 0, float offsetY = 0)
{
base.PopupWindow(parentWindow, offsetX, offsetY);
mAddressEdit.SetFocus();
}
public override void ResizeComponents()
{
base.ResizeComponents();
float curY = mHeight - GS!(20) - mButtonBottomMargin;
mAddressEdit.Resize(GS!(16), curY - GS!(36), mWidth - GS!(16) * 2, GS!(28));
//curY -= 50;
//mAddressEdit.Resize(16, curY - 36, mWidth - 16 * 2, 20);
}
public override void Draw(Graphics g)
{
base.Draw(g);
g.DrawString((mBreakpointKind == .Memory) ? "Breakpoint Address" : "Symbol Name", mAddressEdit.mX, mAddressEdit.mY - GS!(20));
//g.DrawString("Project Directory", mDialogEditWidget.mX, mDialogEditWidget.mY - 20);
}
void SetPending(bool isPending)
{
mIsPending = isPending;
if (isPending)
{
SetFocus();
mAddressEdit.Content.mIsReadOnly = true;
mDefaultButton.mDisabled = true;
}
else
{
mAddressEdit.Content.mIsReadOnly = false;
mDefaultButton.mDisabled = false;
}
}
public override void Close()
{
base.Close();
if (mIsPending)
gApp.mBreakpointPanel.CancelPending();
}
public override void Update()
{
base.Update();
if ((mIsPending) && (gApp.mPendingDebugExprHandler == null))
{
SetPending(false);
}
}
}
}

View file

@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Beefy;
using Beefy.gfx;
using Beefy.theme.dark;
using Beefy.widgets;
namespace IDE.ui
{
public class NewProjectDialog : DarkDialog
{
public PathEditWidget mDirectoryEdit;
public EditWidget mNameEdit;
public DarkComboBox mTargetComboBox;
static String[4] sApplicationTypeNames =
.("Console Application",
"Windows Application",
"Library",
"Custom Build");
public bool mDirChanged;
public String mDirBase ~ delete _;
public this() : base("Create New Project", "")
{
}
public override void CalcSize()
{
mWidth = GS!(320);
mHeight = GS!(200);
}
bool CreateProject()
{
var app = IDEApp.sApp;
String projName = scope String();
mNameEdit.GetText(projName);
projName.Trim();
String projDirectory = scope String();
mDirectoryEdit.GetText(projDirectory);
projDirectory.Trim();
bool isNameValid = projName.Length > 0;
for (int32 i = 0; i < projName.Length; i++)
{
char8 c = projName[i];
if ((!c.IsLetterOrDigit) && (c != '-') && (c != ' ') && (c != '_'))
isNameValid = false;
}
if (!isNameValid)
{
mNameEdit.SetFocus();
app.Fail("Invalid project name. The project name can only consist of alphanumeric char8acters, spaces, dashes, and underscores.");
return false;
}
var otherProject = app.mWorkspace.FindProject(projName);
if (otherProject != null)
{
mNameEdit.SetFocus();
app.Fail("A project with this name already exists in the workspace.");
return false;
}
if (!Directory.Exists(projDirectory))
{
if (Directory.CreateDirectory(projDirectory) case .Err)
{
mDirectoryEdit.SetFocus();
app.Fail("Invalid project directory");
return false;
}
}
String projectFilePath = scope String()..Append(projDirectory, "/BeefProj.toml");
if (File.Exists(projectFilePath))
{
gApp.Fail(scope String()..AppendF("A Beef projects already exists at '{0}'", projDirectory));
return false;
}
Project.TargetType targetType = .BeefWindowsApplication;
for (var applicationTypeName in sApplicationTypeNames)
{
if (applicationTypeName == mTargetComboBox.Label)
{
targetType = (Project.TargetType)@applicationTypeName;
}
}
IDEUtils.FixFilePath(projDirectory);
app.CreateProject(projName, projDirectory, targetType);
app.mWorkspace.SetChanged();
return true;
}
public void UpdateProjectDir()
{
if ((!mDirChanged) && (!mDirBase.IsEmpty))
{
String dirPath = scope .();
dirPath.Append(mDirBase);
dirPath.Append(Path.DirectorySeparatorChar);
mNameEdit.GetText(dirPath);
mDirectoryEdit.SetText(dirPath);
}
}
public void Init()
{
mDefaultButton = AddButton("Create", new (evt) => { if (!CreateProject()) evt.mCloseDialog = false; });
mEscButton = AddButton("Cancel", new (evt) => Close());
mNameEdit = AddEdit("NewProject");
mNameEdit.mOnContentChanged.Add(new (dlg) =>
{
UpdateProjectDir();
});
if (gApp.mWorkspace.IsInitialized)
mDirBase = new String(gApp.mWorkspace.mDir);
else
mDirBase = new String();
mDirectoryEdit = new PathEditWidget(.Folder);
AddEdit(mDirectoryEdit);
mDirectoryEdit.mOnContentChanged.Add(new (dlg) =>
{
if (mDirectoryEdit.mHasFocus)
mDirChanged = true;
});
UpdateProjectDir();
mTargetComboBox = new DarkComboBox();
mTargetComboBox.Label = sApplicationTypeNames[0];
mTargetComboBox.mPopulateMenuAction.Add(new (dlg) =>
{
for (var applicationTypeName in sApplicationTypeNames)
{
var item = dlg.AddItem(applicationTypeName);
item.mOnMenuItemSelected.Add(new (item) =>
{
mTargetComboBox.Label = item.mLabel;
MarkDirty();
});
}
});
AddWidget(mTargetComboBox);
mTabWidgets.Add(mTargetComboBox);
}
public override void PopupWindow(WidgetWindow parentWindow, float offsetX = 0, float offsetY = 0)
{
base.PopupWindow(parentWindow, offsetX, offsetY);
mNameEdit.SetFocus();
}
public override void ResizeComponents()
{
base.ResizeComponents();
float curY = mHeight - GS!(20) - mButtonBottomMargin;
mTargetComboBox.Resize(GS!(16), curY - GS!(36), mWidth - GS!(16) * 2, GS!(28));
curY -= GS!(40);
mDirectoryEdit.Resize(GS!(16), curY - GS!(36), mWidth - GS!(16) * 2, GS!(24));
curY -= GS!(50);
mNameEdit.Resize(GS!(16), curY - GS!(36), mWidth - GS!(16) * 2, GS!(24));
}
public override void Draw(Graphics g)
{
base.Draw(g);
g.DrawString("Project Name", mNameEdit.mX, mNameEdit.mY - GS!(20));
g.DrawString("Project Directory", mDirectoryEdit.mX, mDirectoryEdit.mY - GS!(20));
}
}
}

View file

@ -0,0 +1,380 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Beefy;
using Beefy.events;
using Beefy.gfx;
using Beefy.theme.dark;
using Beefy.widgets;
using System.Diagnostics;
namespace IDE.ui
{
class OpenFileInSolutionDialog : DarkDialog
{
class TimeEntry
{
public DateTime mLastWriteTime;
public DateTime mCheckedTime;
}
protected class EntryListViewItem : DarkListViewItem
{
public override void Draw(Graphics g)
{
if ((mColumnIdx == 3) && (Label.IsEmpty))
{
var pathItem = GetSubItem(2);
DateTime lastWriteTime = GetLastWriteTime(pathItem.Label);
String label = scope String();
lastWriteTime.ToShortDateString(label);
label.Append(" ");
lastWriteTime.ToShortTimeString(label);
Label = label;
}
base.Draw(g);
}
}
protected class EntryListView : DarkListView
{
protected override ListViewItem CreateListViewItem()
{
return new EntryListViewItem();
}
}
public static Dictionary<String, int32> sMRU = new .() ~
{
for (let key in _.Keys)
delete key;
delete _;
};
public static int32 sCurrentMRUIndex = 1;
static Dictionary<String, TimeEntry> sTimeCache = new .() ~ DeleteDictionyAndKeysAndItems!(_);
protected EntryListView mFileList;
EditWidget mEditWidget;
List<ProjectSource> mProjectSourceList = new .() ~ delete _;
public bool mFilterChanged;
public volatile bool mExitingThread;
public Thread mDateThread;
public this()
{
mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable;
AddOkCancelButtons(new (evt) => { GotoFile(); }, null, 0, 1);
//mApplyButton = AddButton("Apply", (evt) => { evt.mCloseDialog = false; ApplyChanges(); });
Title = "Open File in Workspace";
mButtonBottomMargin = GS!(6);
mButtonRightMargin = GS!(6);
mFileList = new EntryListView();
mFileList.InitScrollbars(false, true);
mFileList.mAllowMultiSelect = false;
mFileList.mOnItemMouseDown.Add(new => ValueMouseDown);
ListViewColumn column = mFileList.AddColumn(GS!(200), "File");
column.mMinWidth = GS!(100);
column = mFileList.AddColumn(GS!(80), "Project");
column = mFileList.AddColumn(GS!(200), "Path");
column = mFileList.AddColumn(GS!(200), "Modified");
AddWidget(mFileList);
mTabWidgets.Add(mFileList);
mEditWidget = AddEdit("");
mEditWidget.mOnKeyDown.Add(new => EditKeyDownHandler);
mEditWidget.mOnContentChanged.Add(new (evt) => { mFilterChanged = true; });
}
void ShutdownThread()
{
if (mDateThread != null)
{
mExitingThread = true;
mDateThread.Join();
mDateThread = null;
}
}
void EditKeyDownHandler(KeyDownEvent evt)
{
switch (evt.mKeyCode)
{
case .Up,
.Down,
.PageUp,
.PageDown:
mFileList.KeyDown(evt.mKeyCode, false);
default:
}
if (evt.mKeyFlags == .Ctrl)
{
switch (evt.mKeyCode)
{
case .Home,
.End:
mFileList.KeyDown(evt.mKeyCode, false);
default:
}
}
}
public void ValueMouseDown(ListViewItem clickedItem, float x, float y, int32 btnNum, int32 btnCount)
{
DarkListViewItem item = (DarkListViewItem)clickedItem.GetSubItem(0);
mFileList.GetRoot().SelectItemExclusively(item);
mFileList.SetFocus();
if ((btnNum == 0) && (btnCount > 1))
{
GotoFile();
}
}
void FilterFilesFolder(String filterString, ProjectFolder projectFolder)
{
for (var projectEntry in projectFolder.mChildItems)
{
var childFolder = projectEntry as ProjectFolder;
if (childFolder != null)
FilterFilesFolder(filterString, childFolder);
var projectSource = projectEntry as ProjectSource;
if (projectSource != null)
{
String fileName = scope String();
Path.GetFileName(projectSource.mPath, fileName);
if (filterString.Length > 0)
{
if (fileName.IndexOf(filterString, true) == -1)
continue;
}
mProjectSourceList.Add(projectSource);
}
}
}
int CompareFileNames(String pathA, String pathB)
{
int pathStartA = pathA.LastIndexOf(IDEUtils.cNativeSlash);
int pathStartB = pathB.LastIndexOf(IDEUtils.cNativeSlash);
int lenA = pathA.Length - pathStartA - 1;
int lenB = pathB.Length - pathStartB - 1;
//int result = String.CompareOrdinal(pathA, pathStartA + 1, pathB, pathStartB + 1, Math.Min(lenA, lenB));
int result = String.Compare(pathA, pathStartA + 1, pathB, pathStartB + 1, Math.Min(lenA, lenB), true);
/*if (result == 0)
result = lenA - lenB;*/
return result;
}
public static DateTime GetLastWriteTime(StringView path)
{
var fixedPath = scope String(path);
IDEUtils.MakeComparableFilePath(fixedPath);
bool added = sTimeCache.TryAdd(fixedPath, var keyPtr, var valuePtr);
if (added)
{
*keyPtr = new String(fixedPath);
TimeEntry te = new .();
te.mLastWriteTime = File.GetLastWriteTime(path);
te.mCheckedTime = DateTime.Now;
*valuePtr = te;
return te.mLastWriteTime;
}
else
{
TimeEntry te = *valuePtr;
if ((DateTime.Now - te.mCheckedTime).TotalSeconds > 60)
{
te.mCheckedTime = DateTime.Now;
te.mLastWriteTime = File.GetLastWriteTime(path);
}
return te.mLastWriteTime;
}
}
public static void ClearWriteTime(StringView path)
{
var fixedPath = scope String(path);
IDEUtils.MakeComparableFilePath(fixedPath);
if (sTimeCache.TryGetValue(fixedPath, var key, var value))
{
value.mCheckedTime = default;
}
}
void FilterFiles()
{
String filterString = scope String();
mEditWidget.GetText(filterString);
filterString.Trim();
mProjectSourceList.Clear();
var root = mFileList.GetRoot();
root.Clear();
for (var project in IDEApp.sApp.mWorkspace.mProjects)
{
FilterFilesFolder(filterString, project.mRootFolder);
}
/*var selectedItem = null;// root.FindSelectedItem();
if ((selectedItem == null) && (root.GetChildCount() > 0))
{
selectedItem = root.GetChildAtIndex(0);
root.SelectItemExclusively(selectedItem);
}*/
mProjectSourceList.Sort(scope (itemA, itemB) => CompareFileNames(itemA.mPath, itemB.mPath));
for (var projectSource in mProjectSourceList)
{
String fileName = scope String();
Path.GetFileName(projectSource.mPath, fileName);
var listViewItem = mFileList.GetRoot().CreateChildItem();
listViewItem.Label = fileName;
var subListViewItem = listViewItem.CreateSubItem(1);
subListViewItem.Label = projectSource.mProject.mProjectName;
String fullPath = scope String();
projectSource.GetFullImportPath(fullPath);
subListViewItem = listViewItem.CreateSubItem(2);
subListViewItem.Label = fullPath;
subListViewItem = listViewItem.CreateSubItem(3);
}
ListViewItem bestItem = null;
int32 bestPri = -1;
for (int32 childIdx = 0; childIdx < root.GetChildCount(); childIdx++)
{
var listViewItem = root.GetChildAtIndex(childIdx);
var projectSource = mProjectSourceList[childIdx];
int32 pri;
sMRU.TryGetValue(projectSource.mPath, out pri);
if (pri > bestPri)
{
bestItem = listViewItem;
bestPri = pri;
}
}
if (bestItem != null)
{
mFileList.GetRoot().SelectItemExclusively(bestItem);
mFileList.EnsureItemVisible(bestItem, true);
}
/*ShutdownThread();
mExitingThread = true;
mDateThread = new Thread(CheckFileDates);
mDateThread.Start();*/
}
void GotoFile()
{
Close();
var root = mFileList.GetRoot();
var selectedListViewItem = root.FindFirstSelectedItem();
if (selectedListViewItem != null)
{
var itemIdx = root.mChildItems.IndexOf(selectedListViewItem);
var projectSource = mProjectSourceList[itemIdx];
gApp.RecordHistoryLocation(true);
gApp.ShowProjectItem(projectSource, false);
if (sMRU.TryAdd(projectSource.mPath, var keyPtr, var valuePtr))
{
*keyPtr = new String(projectSource.mPath);
*valuePtr = sCurrentMRUIndex++;
}
}
}
public override void AddedToParent()
{
base.AddedToParent();
mEditWidget.SetFocus();
FilterFiles();
}
public override void ResizeComponents()
{
base.ResizeComponents();
//var font = DarkTheme.sDarkTheme.mSmallFont;
float insetSize = GS!(6);
mFileList.Resize(insetSize, insetSize, mWidth - insetSize - insetSize, mHeight - GS!(66));
mEditWidget.Resize(insetSize, mFileList.mY + mFileList.mHeight + insetSize, mWidth - insetSize - insetSize, GS!(22));
}
public override void CalcSize()
{
mWidth = GS!(660);
mHeight = GS!(512);
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
void Outline(Graphics g, Widget widget, int32 inflateX, int32 inflateY, uint32 color)
{
using (g.PushColor(color))
{
g.OutlineRect(widget.mX - inflateX, widget.mY - inflateY, widget.mWidth + inflateX * 2, widget.mHeight + inflateY * 2);
}
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
//Outline(g, mCategorySelector, 0, 0, 0xFF404040);
//Outline(g, mCategorySelector, -1, -1, 0xFF202020);
Outline(g, mFileList, 0, 0, IDEApp.cDialogOutlineLightColor);
Outline(g, mFileList, -1, -1, IDEApp.cDialogOutlineDarkColor);
}
void CheckFileDates()
{
//
}
public override void Update()
{
base.Update();
if (mFilterChanged)
{
FilterFiles();
mFilterChanged = false;
}
}
}
}

281
IDE/src/ui/OutputPanel.bf Normal file
View file

@ -0,0 +1,281 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using Beefy.widgets;
using Beefy.utils;
using Beefy.gfx;
using Beefy.theme.dark;
namespace IDE.ui
{
public class OutputPanel : TextPanel
{
struct QueuedDisplayChange
{
public int32 mOfs;
public int32 mLen;
public uint8 mDisplayTypeId;
public Widget mWidget;
public this(int ofs, int len, uint8 displayType)
{
mOfs = (int32)ofs;
mLen = (int32)len;
mDisplayTypeId = displayType;
mWidget = null;
}
public this(int ofs, Widget addWidget)
{
mOfs = (int32)ofs;
mLen = 0;
mDisplayTypeId = 0;
mWidget = addWidget;
}
}
struct InlineWidgetEntry
{
public Widget mWidget;
public float mOfsX;
public float mOfsY;
public int32 mLine;
public int32 mLineChar;
}
public OutputWidget mOutputWidget;
String mQueuedText = new String() ~ delete _;
List<QueuedDisplayChange> mQueuedDisplayChanges = new List<QueuedDisplayChange>() ~ delete _;
List<InlineWidgetEntry> mInlineWidgets = new List<InlineWidgetEntry>() ~ delete _;
public int32 mHoverWatchLine;
public override SourceEditWidget EditWidget
{
get
{
return mOutputWidget;
}
}
public this()
{
mOutputWidget = new OutputWidget();
mOutputWidget.Content.mIsMultiline = true;
mOutputWidget.Content.mWordWrap = false;
mOutputWidget.InitScrollbars(true, true);
var darkEditContent = (OutputWidgetContent)mOutputWidget.Content;
darkEditContent.mOnEscape = new () => EscapeHandler();
darkEditContent.mFont = IDEApp.sApp.mCodeFont;
//darkEditContent.mFont = DarkTheme.sDarkTheme.mSmallFont;
darkEditContent.mUnfocusedHiliteColor = (darkEditContent.mHiliteColor & 0x00FFFFFF) | 0x60000000;
AddWidget(mOutputWidget);
}
public this(bool remapToHighestCompileIdx) : this()
{
var darkEditContent = (OutputWidgetContent)mOutputWidget.Content;
darkEditContent.mRemapToHighestCompileIdx = remapToHighestCompileIdx;
}
public override void Serialize(StructuredData data)
{
data.Add("Type", "OutputPanel");
}
public override bool Deserialize(StructuredData data)
{
return base.Deserialize(data);
}
public override void FocusForKeyboard()
{
mOutputWidget.mEditWidgetContent.mSelection = null;
mOutputWidget.mEditWidgetContent.CursorLineAndColumn = EditWidgetContent.LineAndColumn(mOutputWidget.mEditWidgetContent.GetLineCount() - 1, 0);
mOutputWidget.mEditWidgetContent.EnsureCursorVisible();
}
public override void Clear()
{
scope AutoBeefPerf("OutputPanel.Clear");
mOutputWidget.SetText("");
for (var widgetEntry in mInlineWidgets)
{
widgetEntry.mWidget.RemoveSelf();
delete widgetEntry.mWidget;
}
mInlineWidgets.Clear();
}
public override void RehupScale(float oldScale, float newScale)
{
base.RehupScale(oldScale, newScale);
for (var widgetEntry in mInlineWidgets)
{
var widget = widgetEntry.mWidget;
mOutputWidget.Content.GetTextCoordAtLineChar(widgetEntry.mLine, widgetEntry.mLineChar, var xOfs, var yOfs);
widget.mX = widgetEntry.mOfsX + xOfs;
widget.mY = widgetEntry.mOfsY + yOfs;
}
}
public void Write(StringView text)
{
mQueuedText.Append(text);
}
void UpdateHoverWatch()
{
base.Update();
if (mWidgetWindow == null)
return;
if (!CheckAllowHoverWatch())
return;
if (IDEApp.sApp.HasPopupMenus())
return;
/*if (mHoverWatchRect.HasValue)
{
float x;
float y;
RootToSelfTranslate(mWidgetWindow.mMouseX, mWidgetWindow.mMouseY, out x, out y);
if (mHoverWatchRect.Value.Contains(x, y))
return;
} */
if ((mHoverWatch != null) && (mHoverWatch.mCloseDelay == 0))
{
float x;
float y;
EditWidget.Content.RootToSelfTranslate(mWidgetWindow.mMouseX, mWidgetWindow.mMouseY, out x, out y);
int line;
int column;
EditWidget.Content.GetLineAndColumnAtCoord(x, y, out line, out column);
if (line == mHoverWatchLine)
return;
mHoverWatch.Close();
}
}
public override void Update()
{
base.Update();
var editData = mOutputWidget.mEditWidgetContent.mData;
int lineStartZero = -1;
if (editData.mLineStarts != null)
{
lineStartZero = editData.mLineStarts[0];
Debug.Assert(lineStartZero <= editData.mTextLength);
}
UpdateHoverWatch();
if (mQueuedText.Length > 0)
{
scope AutoBeefPerf("OutputPanel.Update:QueuedText");
int line;
int lineChar;
mOutputWidget.Content.GetLineCharAtIdx(mOutputWidget.Content.mData.mTextLength, out line, out lineChar);
mOutputWidget.Content.mAutoHorzScroll = false;
mOutputWidget.Content.mEnsureCursorVisibleOnModify = mOutputWidget.Content.IsLineVisible(line);
int startLen = editData.mTextLength;
mOutputWidget.Content.AppendText(mQueuedText);
mOutputWidget.Content.mAutoHorzScroll = true;
mOutputWidget.Content.mEnsureCursorVisibleOnModify = true;
Debug.Assert(editData.mTextLength == startLen + mQueuedText.Length);
for (var queuedDisplayChange in mQueuedDisplayChanges)
{
if (queuedDisplayChange.mWidget != null)
{
var widget = queuedDisplayChange.mWidget;
mOutputWidget.mEditWidgetContent.AddWidget(queuedDisplayChange.mWidget);
mOutputWidget.Content.GetLineCharAtIdx(startLen + queuedDisplayChange.mOfs, out line, out lineChar);
mOutputWidget.Content.GetTextCoordAtLineChar(line, lineChar, var xOfs, var yOfs);
InlineWidgetEntry widgetEntry;
widgetEntry.mOfsX = widget.mX;
widgetEntry.mOfsY = widget.mY;
widgetEntry.mLine = (.)line;
widgetEntry.mLineChar = (.)lineChar;
widgetEntry.mWidget = queuedDisplayChange.mWidget;
mInlineWidgets.Add(widgetEntry);
widget.mX = widgetEntry.mOfsX + xOfs;
widget.mY = widgetEntry.mOfsY + yOfs;
}
else
{
for (int i = startLen + queuedDisplayChange.mOfs; i < startLen + queuedDisplayChange.mOfs + queuedDisplayChange.mLen; i++)
editData.mText[i].mDisplayTypeId = queuedDisplayChange.mDisplayTypeId;
}
}
mQueuedText.Clear();
mQueuedDisplayChanges.Clear();
}
}
public void WriteSmart(StringView text)
{
for (var line in text.Split('\n'))
{
if (@line.Pos != 0)
Write("\n");
if ((line.StartsWith("ERROR:")) || (line.StartsWith("ERROR(")))
{
if ((gApp.mRunningTestScript) && (!gApp.mFailed))
{
gApp.Fail(scope String()..Append(line));
continue;
}
mQueuedDisplayChanges.Add(QueuedDisplayChange(mQueuedText.Length, "ERROR".Length, 12));
}
if ((line.StartsWith("WARNING:")) || (line.StartsWith("WARNING(")))
{
mQueuedDisplayChanges.Add(QueuedDisplayChange(mQueuedText.Length, "WARNING".Length, 13));
}
Write(line);
}
}
public void AddInlineWidget(Widget widget)
{
mQueuedDisplayChanges.Add(QueuedDisplayChange(mQueuedText.Length, widget));
}
public void GotoNextSourceReference()
{
var content = (OutputWidgetContent)mOutputWidget.Content;
int curLine;
int lineChar;
content.GetLineCharAtIdx(content.CursorTextPos, out curLine, out lineChar);
int lineCount = content.GetLineCount();
for (int lineOfs = 1; lineOfs < lineCount + 1; lineOfs++)
{
int lineIdx = (curLine + lineOfs) % lineCount;
if (content.GotoRefrenceAtLine(lineIdx))
break;
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
mOutputWidget.Resize(0, 0, width, height);
}
}
}

276
IDE/src/ui/OutputWidget.bf Normal file
View file

@ -0,0 +1,276 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy.widgets;
using Beefy.theme.dark;
using Beefy.gfx;
namespace IDE.ui
{
public class OutputWidgetContent : SourceEditWidgetContent
{
public bool mRemapToHighestCompileIdx;
public this()
{
mIsReadOnly = true;
}
public Event<Func<int, int, bool>> mGotoReferenceEvent ~ _.Dispose();
public bool GotoRefrenceAtLine(int line, int lineOfs = 0)
{
//bool selectLine = true;
//Match match = null;
int lineStart = 0;
int lineEnd = 0;
int lineCheck = Math.Max(0, line + lineOfs);
GetLinePosition(lineCheck, out lineStart, out lineEnd);
mSelection = EditSelection(lineStart, lineEnd);
var selectionText = scope String();
GetSelectionText(selectionText);
//if (selectionText.Length > 512)
//return false;
//int idx = selectionText.IndexOf("line ");
int32 errLine = 0;
int32 errLineChar = 0;
String filePath = null;
bool success = false;
for (var dlg in mGotoReferenceEvent)
if (dlg(line, lineOfs))
{
success = true;
break;
}
int32 inTextPos = -1;
for (int32 i = 1; i < Math.Min(512, selectionText.Length); i++)
{
if (success)
break;
if (selectionText[i] == ':')
{
if (selectionText[i - 1] == ')')
{
int32 startIdx = i;
while ((startIdx > 0) && (selectionText[startIdx - 1] != '('))
startIdx--;
String lineStr = scope String(selectionText, startIdx, i - startIdx - 1);
var lineResult = Int32.Parse(lineStr);
if (lineResult case .Ok(out errLine))
{
//errLine = lineResult.Value;
filePath = scope:: String(selectionText, 0, startIdx - 1);
filePath.Trim();
if ((filePath.Contains('\\')) || (filePath.Contains('/')))
break;
}
}
else
{
int32 startIdx = i;
while ((startIdx > 0) && (selectionText[startIdx - 1].IsNumber))
startIdx--;
if ((startIdx > 0) && (selectionText[startIdx - 1] == ':'))
{
// :num:
int32 columnStartIdx = startIdx;
startIdx--;
while ((startIdx > 0) && (selectionText[startIdx - 1].IsNumber))
startIdx--;
String lineStr = scope String(selectionText, startIdx, columnStartIdx - startIdx - 1);
String columnStr = scope String(selectionText, columnStartIdx, i - columnStartIdx);
if ((startIdx > 0) && (selectionText[startIdx - 1] == ':'))
{
// fileName:line:column:
var lineResult = Int32.Parse(lineStr);
var columnResult = Int32.Parse(columnStr);
if ((lineResult case .Ok(out errLine)) && (columnResult case .Ok(out errLineChar)))
{
//errLine = lineResult.Value;
//errLineChar = columnResult.Value;
filePath = scope:: String(selectionText, 0, startIdx - 1);
filePath.Trim();
}
//lineResult.Dispose();
//columnResult.Dispose();
}
continue;
}
int32 endIdx = i;
while ((endIdx < selectionText.Length - 1) && (selectionText[endIdx + 1].IsNumber))
endIdx++;
String lineStr = scope String(selectionText, startIdx, i - startIdx);
String columnStr = scope String(selectionText, i + 1, endIdx - i);
var lineResult = Int32.Parse(lineStr);
var columnResult = Int32.Parse(columnStr);
if ((lineResult case .Ok) && (columnResult case .Ok))
{
errLine = lineResult;
errLineChar = columnResult;
}
/*if (lineResult.HasValue && columnResult.HasValue)
{
errLine = lineResult.Value;
errLineChar = columnResult.Value;
}
lineResult.Dispose();
columnResult.Dispose();*/
}
}
// Match " in "
if ((errLine > 0) && (i > 3) && (errLine != -1) && (selectionText[i] == ' ') && (selectionText[i - 1] == 'n') && (selectionText[i - 2] == 'i') && (selectionText[i - 3] == ' '))
{
inTextPos = i + 1;
//filePath = stack String(selectionText, i + 1);
//break;
}
}
if (inTextPos != -1)
{
filePath = scope:: String(selectionText, inTextPos);
}
if (filePath == null)
{
if (selectionText.StartsWith("ERROR: "))
{
int linePos = selectionText.IndexOf(" at line ");
if (linePos != -1)
{
int lineStartIdx = linePos + " at line ".Length;
int spacePos = selectionText.IndexOf(" in ", lineStartIdx);
if (spacePos != -1)
{
int nameStartPos = spacePos + " in ".Length;
if (int32.Parse(.(selectionText, lineStartIdx, spacePos - lineStartIdx)) case .Ok(out errLine))
{
filePath = scope:: String(selectionText, nameStartPos);
}
}
}
}
}
if ((errLine != -1) && (errLineChar != -1) && (filePath != null))
{
IDEApp.sApp.CheckProjectRelativePath(filePath);
IDEUtils.FixFilePath(filePath);
IDEApp.sApp.ShowSourceFileLocation(filePath, -1, mRemapToHighestCompileIdx ? IDEApp.sApp.mWorkspace.GetHighestCompileIdx() : -1, errLine - 1, errLineChar - 1, LocatorType.Always);
success = true;
}
if (success)
{
bool selectLine = lineOfs == 0;
if (!selectLine)
mSelection = null;
CursorTextPos = lineStart;
EnsureCursorVisible();
return true;
}
return false;
}
public override void MouseClicked(float x, float y, int32 btn)
{
base.MouseClicked(x, y, btn);
if (btn == 1)
{
float useX = x;
float useY = y;
ClampMenuCoords(ref useX, ref useY);
Menu menu = new Menu();
var menuItem = menu.AddItem("Clear All");
var panel = mParent.mParent.mParent as TextPanel;
menuItem.mOnMenuItemSelected.Add(new (evt) =>
{
if (panel != null)
panel.Clear();
else
ClearText();
});
MenuWidget menuWidget = DarkTheme.sDarkTheme.CreateMenuWidget(menu);
menuWidget.Init(this, useX, useY);
}
}
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
{
if ((btn == 0) && (btnCount > 1))
{
for (int32 lineOfs = 0; lineOfs >= -1; lineOfs--)
if (GotoRefrenceAtLine(CursorLineAndColumn.mLine, lineOfs))
return;
}
base.MouseDown(x, y, btn, btnCount);
}
public override void KeyDown(KeyCode keyCode, bool isRepeat)
{
base.KeyDown(keyCode, isRepeat);
if (keyCode == .Apps)
{
GetTextCoordAtCursor(var x, var y);
MouseClicked(x, y, 1);
}
}
}
public class OutputWidget : SourceEditWidget
{
public this()
: base(null, new OutputWidgetContent())
{
}
public override void DrawAll(Beefy.gfx.Graphics g)
{
base.DrawAll(g);
/*for (int i < 10)
{
var testStr = scope String();
for (int j < 10)
{
Font.StrEncodeColor(0xfffebd57, testStr);
testStr.Append('A' + j);
Font.StrEncodePopColor(testStr);
}
g.DrawString(testStr, 20, 300 + i * 20);
}*/
}
}
}

232
IDE/src/ui/Panel.bf Normal file
View file

@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using Beefy.widgets;
using Beefy.utils;
using Beefy.theme.dark;
using Beefy.events;
namespace IDE.ui
{
interface IDocumentPanel
{
}
public class Panel : Widget
{
public int32 mLastFocusAppUpdateCnt;
public bool mAutoDelete = true;
public List<Widget> mTabWidgets = new List<Widget>() ~ delete _;
public bool mShowingRightClickMenu;
/// Unscaled
public virtual float TabWidthOffset
{
get
{
return 50;
}
}
public override void GotFocus()
{
base.GotFocus();
mLastFocusAppUpdateCnt = gApp.mUpdateCnt;
}
public override void ParentDeleted()
{
if (mAutoDelete)
base.ParentDeleted();
}
public override void AddedToParent()
{
base.AddedToParent();
mLastFocusAppUpdateCnt = gApp.mUpdateCnt;
}
public override void RemovedFromParent(Widget previousParent, WidgetWindow window)
{
base.RemovedFromParent(previousParent, window);
}
public virtual void FocusForKeyboard()
{
}
public override void Serialize(StructuredData data)
{
}
public override bool Deserialize(StructuredData data)
{
return true;
}
public static Panel Create(StructuredData data)
{
var type = scope String();
data.GetString("Type", type);
Panel panel = null;
if (type == "CallStackPanel")
panel = gApp.mCallStackPanel;
else if (type == "BreakpointPanel")
panel = gApp.mBreakpointPanel;
else if (type == "ProfilePanel")
panel = gApp.mProfilePanel;
else if (type == "OutputPanel")
{
panel = gApp.mOutputPanel;
}
else if (type == "ImmediatePanel")
{
panel = gApp.mImmediatePanel;
}
else if (type == "FindResultsPanel")
{
panel = gApp.mFindResultsPanel;
}
else if (type == "ProjectPanel")
{
panel = gApp.mProjectPanel;
}
else if (type == "ClassViewPanel")
{
panel = gApp.mClassViewPanel;
}
else if (type == "PropertiesPanel")
{
panel = gApp.mPropertiesPanel;
}
else if (type == "SourceViewPanel")
{
panel = new SourceViewPanel();
}
else if (type == "DisassemblyPanel")
{
var disassemblyPanel = new DisassemblyPanel();
disassemblyPanel.mIsInitialized = true;
panel = disassemblyPanel;
}
else if (type == "ThreadPanel")
{
panel = gApp.mThreadPanel;
}
else if (type == "WatchPanel")
{
panel = gApp.mWatchPanel;
}
else if (type == "AutoWatchPanel")
{
panel = gApp.mAutoWatchPanel;
}
else if (type == "MemoryPanel")
{
panel = gApp.mMemoryPanel;
}
else if (type == "AutoCompletePanel")
{
panel = gApp.mAutoCompletePanel;
}
else if (type == "ModulePanel")
{
panel = gApp.mModulePanel;
}
if (panel != null)
{
if (!panel.Deserialize(data))
{
delete panel;
return null;
}
}
Debug.Assert(panel.mParent == null);
Debug.Assert(panel != null);
return panel;
}
public void RehupScale()
{
RehupScale(DarkTheme.sScale, DarkTheme.sScale);
}
protected virtual void ShowRightClickMenu(Widget relWidget, float x, float y)
{
}
public void DoShowRightClickMenu(Widget relWidget, float x, float y)
{
mShowingRightClickMenu = true;
ShowRightClickMenu(relWidget, x, y);
mShowingRightClickMenu = false;
}
public void ListViewItemMouseDown(ListViewItem item, float x, float y, int32 btnNum, int32 btnCount)
{
var listView = item.mListView;
listView.SetFocus();
var baseItem = item.GetSubItem(0);
if (btnNum == 1)
{
if (!baseItem.Selected)
listView.GetRoot().SelectItem(baseItem, true);
}
else
listView.GetRoot().SelectItem(baseItem, true);
}
public void ListViewItemMouseClicked(ListViewItem item, float x, float y, int32 btnNum)
{
if (btnNum == 1)
{
var listView = item.mListView;
item.SelfToOtherTranslate(listView.GetRoot(), x, y, var aX, var aY);
DoShowRightClickMenu(listView.GetRoot(), aX, aY);
}
}
public void ListViewKeyDown_ShowMenu(KeyDownEvent evt)
{
if (evt.mKeyCode == .Apps)
{
var listView = (ListView)evt.mSender;
ShowRightClickMenu(listView);
}
}
protected void ShowRightClickMenu(ListView listView)
{
var focusedItem = listView.GetRoot().FindFocusedItem();
if (focusedItem != null)
{
focusedItem.SelfToOtherTranslate(listView.GetRoot(), 0, 0, var x, var y);
x += GS!(20);
y += GS!(20);
IDEUtils.ClampMenuCoords(ref x, ref y, listView, scope .(0, 0, GS!(32), GS!(32)));
DoShowRightClickMenu(listView.GetRoot(), x, y);
}
}
// To group newly-opened panels in frames that make sense
public virtual bool HasAffinity(Widget otherPanel)
{
return otherPanel.GetType() == GetType();
}
public virtual bool HandleTab(int dir)
{
return Widget.HandleTab(dir, mTabWidgets);
}
}
}

150
IDE/src/ui/PanelHeader.bf Normal file
View file

@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy.gfx;
using Beefy.theme.dark;
using Beefy.widgets;
using Beefy.geom;
namespace IDE.ui
{
public class PanelHeader : Widget
{
public List<DarkButton> mButtons = new List<DarkButton>() ~ delete _;
public String mLabel ~ delete _;
public String mTooltipText ~ delete _;
public float mFlashPct;
public int mBaseHeight = 32;
public bool mButtonsOnBottom;
public String Label
{
get
{
return mLabel;
}
set
{
String.NewOrSet!(mLabel, value);
}
}
public override void Draw(Graphics g)
{
using (g.PushColor(0xFFF0BFA4))
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.VertScrollbarThumb), 0, 0, mWidth, mHeight);
g.SetFont(DarkTheme.sDarkTheme.mSmallFont);
float y = GS!(6);
using (g.PushColor(0xFFFFFFFF))
{
for (var str in mLabel.Split('\n'))
{
float maxTextLen = mWidth - GS!(12 + 12);
if ((mButtons.Count > 0) && (!@str.HasMore))
maxTextLen = mButtons[0].mX - GS!(12 + 2);
g.DrawString(scope String(str), GS!(12), y, FontAlign.Left, maxTextLen, FontOverflowMode.Ellipsis);
y += g.mFont.GetLineSpacing();
}
}
if (mFlashPct > 0)
{
float showPct = Math.Max(0.0f, (Math.Sin(mFlashPct * Math.PI_f * 4))) * 0.25f;
using (g.PushColor(Color.Get(0xFFFFFFFF, showPct)))
g.FillRect(0, 0, mWidth, mHeight);
}
}
void ResizeComponents()
{
var font = DarkTheme.sDarkTheme.mSmallFont;
float x;
x = mWidth - GS!(10);
for (int buttonIdx = mButtons.Count - 1; buttonIdx >= 0; buttonIdx--)
{
var button = mButtons[buttonIdx];
float width = font.GetWidth(button.mLabel) + GS!(24);
x -= width;
button.Resize(x, mHeight - GS!(28), width, GS!(22));
x -= GS!(8);
button.mVisible = x >= 0;
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
public ButtonWidget AddButton(String label)
{
DarkButton button = new DarkButton();
button.Label = label;
mButtons.Add(button);
AddWidget(button);
return button;
}
public void RemoveButtons()
{
for (var button in mButtons)
{
RemoveWidget(button);
delete button;
}
mButtons.Clear();
}
public void Flash()
{
mFlashPct = 1.0f;
}
public override void Update()
{
base.Update();
if (mFlashPct > 0)
{
mFlashPct = Math.Max(0, mFlashPct - 0.015f);
MarkDirty();
}
if ((mTooltipText != null) && (!DarkTooltipManager.IsTooltipShown(this)))
{
var font = DarkTheme.sDarkTheme.mSmallFont;
var tooltipWidth = font.GetWidth(mTooltipText);
//if (tooltipWidth > mWidth - GS!(8))
{
Point point;
if (DarkTooltipManager.CheckMouseover(this, 25, out point))
{
float showWidth = Math.Max(64, Math.Min(tooltipWidth, mWidth * 0.6f));
float showHeight = font.GetWrapHeight(mTooltipText, showWidth);
var tooltip = DarkTooltipManager.ShowTooltip("", this, point.x, 14, showWidth, showHeight + GS!(42), true, true);
if (tooltip != null)
{
var editWidget = new WatchStringEdit(mTooltipText, null);
tooltip.mRelWidgetMouseInsets = new Insets(0, 0, GS!(-8), 0);
tooltip.mAllowMouseInsideSelf = true;
tooltip.AddWidget(editWidget);
tooltip.mOnResized.Add(new (widget) => editWidget.Resize(GS!(6), GS!(6), widget.mWidth - GS!(6) * 2, widget.mHeight - GS!(6) * 2));
tooltip.mOnResized(tooltip);
}
}
}
}
//if (gApp.UpdateM)
}
}
}

220
IDE/src/ui/PanelPopup.bf Normal file
View file

@ -0,0 +1,220 @@
using Beefy.theme.dark;
using Beefy.widgets;
using Beefy.events;
using Beefy;
using System;
using Beefy.geom;
using Beefy.gfx;
namespace IDE.ui
{
class PanelPopup : Widget
{
public Panel mPanel;
public BFWindowBase.Flags mWindowFlags = .ClientSized | .NoActivate | .NoMouseActivate | .DestAlpha;
Widget mRelativeWidget;
bool mReverse;
float mMinContainerWidth = 32;
float mMaxContainerWidth = 2048;
Insets mPopupInsets = new .() ~ delete _;
bool mHasClosed;
bool mDeferredClose;
public virtual void CalcSize()
{
}
public virtual float GetReverseAdjust()
{
return GS!(10);
}
public override void Draw(Graphics g)
{
//g.DrawBox(DarkTheme.sDarkTheme.GetImage(.Window), 0, 0, mWidth, mHeight);
/*using (g.PushColor(0x80FF0000))
g.FillRect(0, 0, mWidth, mHeight);*/
using (g.PushColor(0x80000000))
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.DropShadow), GS!(2), 0 + GS!(2), mWidth - GS!(2), mHeight - GS!(2));
base.Draw(g);
using (g.PushColor(0xFFFFFFFF))
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Menu), 0, 0, mWidth - GS!(8), mHeight - GS!(8));
}
public override void Update()
{
base.Update();
if (mDeferredClose)
Close();
}
public virtual void Init(Panel panel, Widget relativeWidget, float x, float y, float width, float height)
{
mPanel = panel;
float curY = y;
WidgetWindow curWidgetWindow = null;
Resize(0, 0, width, height);
bool reverse = false;
bool allowReverse = true;
if ((allowReverse) && (relativeWidget != null))
{
CalcSize();
float minHeight = mHeight;
float screenX;
float screenY;
relativeWidget.SelfToRootTranslate(0, curY, out screenX, out screenY);
screenY += relativeWidget.mWidgetWindow.mClientY;
int wsX;
int wsY;
int wsWidth;
int wsHeight;
BFApp.sApp.GetWorkspaceRect(out wsX, out wsY, out wsWidth, out wsHeight);
float spaceLeft = (wsY + wsHeight) - (screenY);
if (spaceLeft < minHeight)
{
//curY = curY + GetReverseAdjust() - height;
curY = curY - height - GetReverseAdjust();
reverse = true;
}
}
mReverse = reverse;
float screenX = x;
float screenY = curY;
CalcSize();
if (relativeWidget != null)
relativeWidget.SelfToRootTranslate(x, curY, out screenX, out screenY);
screenX += relativeWidget.mWidgetWindow.mClientX;
screenY += relativeWidget.mWidgetWindow.mClientY;
//float screenWidth;
//float screenHeight;
//CalcContainerSize(panel, ref screenX, ref screenY, out screenWidth, out screenHeight);
BFWindowBase.Flags flags = mWindowFlags;
curWidgetWindow = new WidgetWindow((relativeWidget != null) ? relativeWidget.mWidgetWindow : null,
"Popup",
(int32)(screenX), (int32)(screenY),
(int32)width, (int32)height,
flags,
this);
AddWidget(mPanel);
//Resize(0, 0, mWidth, mHeight);
//panel.UpdateScrollbars();
mRelativeWidget = relativeWidget;
WidgetWindow.sOnKeyDown.Add(new => HandleKeyDown);
WidgetWindow.sOnWindowLostFocus.Add(new => WindowLostFocus);
WidgetWindow.sOnMouseDown.Add(new => HandleMouseDown);
WidgetWindow.sOnMouseWheel.Add(new => HandleMouseWheel);
WidgetWindow.sOnWindowMoved.Add(new => HandleWindowMoved);
WidgetWindow.sOnMenuItemSelected.Add(new => HandleSysMenuItemSelected);
/*if (mRelativeWidget != null)
mRelativeWidget.mOnMouseUp.Add(new => HandleMouseUp);*/
curWidgetWindow.SetFocus(this);
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
mPanel.Resize(GS!(1), GS!(0), width - GS!(9), height - GS!(8));
}
public void RemoveHandlers()
{
WidgetWindow.sOnMouseDown.Remove(scope => HandleMouseDown, true);
WidgetWindow.sOnMouseWheel.Remove(scope => HandleMouseWheel, true);
WidgetWindow.sOnWindowLostFocus.Remove(scope => WindowLostFocus, true);
WidgetWindow.sOnWindowMoved.Remove(scope => HandleWindowMoved, true);
WidgetWindow.sOnMenuItemSelected.Remove(scope => HandleSysMenuItemSelected, true);
WidgetWindow.sOnKeyDown.Remove(scope => HandleKeyDown, true);
}
public void Close()
{
if (mHasClosed)
return;
mHasClosed = true;
RemoveHandlers();
//Debug.Assert(mWidgetWindow != null);
if (mWidgetWindow != null)
{
mWidgetWindow.Close();
/*if (mMenu.mOnMenuClosed.HasListeners)
mMenu.mOnMenuClosed(mMenu, mItemSelected);*/
}
}
void HandleMouseWheel(MouseEvent theEvent)
{
HandleMouseDown(theEvent);
}
void HandleMouseDown(MouseEvent theEvent)
{
WidgetWindow widgetWindow = (WidgetWindow)theEvent.mSender;
if (!(widgetWindow.mRootWidget is PanelPopup))
mDeferredClose = true;
//Close();
}
void HandleSysMenuItemSelected(IMenu sysMenu)
{
Close();
}
bool IsMenuWindow(BFWindow window)
{
var newWidgetWindow = window as WidgetWindow;
if (newWidgetWindow != null)
{
if (newWidgetWindow.mRootWidget is PanelPopup)
return true;
}
return false;
}
void WindowLostFocus(BFWindow window, BFWindow newFocus)
{
if (IsMenuWindow(newFocus))
return;
if ((mWidgetWindow != null) && (!mWidgetWindow.mHasFocus))
Close();
}
void HandleKeyDown(KeyDownEvent evt)
{
if (evt.mKeyCode == KeyCode.Escape)
{
evt.mHandled = true;
Close();
}
}
void HandleWindowMoved(BFWindow window)
{
if (IsMenuWindow(window))
return;
Close();
}
}
}

View file

@ -0,0 +1,82 @@
using Beefy;
using Beefy.widgets;
using Beefy.geom;
using System;
namespace IDE.ui
{
class PanelSplitter : Widget
{
public Panel mTopPanel;
public Panel mBottomPanel;
public float mSplitPct = 0.3f;
public Point mDownPoint;
public Action mSplitAction ~ delete _;
public Action mUnsplitAction ~ delete _;
public this(Panel topPanel, Panel bottomPanel)
{
mTopPanel = topPanel;
mBottomPanel = bottomPanel;
}
public override void MouseEnter()
{
base.MouseEnter();
}
public override void MouseLeave()
{
base.MouseLeave();
if (!mMouseDown)
BFApp.sApp.SetCursor(Cursor.Pointer);
}
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
{
base.MouseDown(x, y, btn, btnCount);
mDownPoint = Point(x, y);
}
public override void MouseMove(float x, float y)
{
base.MouseMove(x, y);
BFApp.sApp.SetCursor(Cursor.SizeNS);
if (mMouseDown)
{
float ofsY = mBottomPanel.mY + mHeight;
if (mTopPanel != null)
ofsY = mTopPanel.mY;
float totalHeight = mBottomPanel.mHeight;
float curY = mY + (y - mDownPoint.y) + mHeight /*+ mDownPoint.y*/;
mSplitPct = (curY - ofsY - mHeight) / (totalHeight - ofsY - mHeight);
if ((mSplitPct > 0) && (mTopPanel == null) && (mSplitAction != null))
mSplitAction();
if ((mSplitPct <= 0) && (mTopPanel != null) && (mUnsplitAction != null))
mUnsplitAction();
mBottomPanel.Resize(mBottomPanel.mX, mBottomPanel.mY, mBottomPanel.mWidth, mBottomPanel.mHeight);
}
}
public override void Update()
{
base.Update();
}
public override void Draw(Beefy.gfx.Graphics g)
{
base.Draw(g);
/*using (g.PushColor(0xFFFF0000))
g.FillRect(0, 0, mWidth, mHeight);*/
}
}
}

View file

@ -0,0 +1,230 @@
using Beefy.theme.dark;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Generic;
namespace IDE.ui
{
class PathEditWidget : ExpressionEditWidget
{
enum PathKind
{
Unknown,
Folder,
File
}
class DirectoryTask : Task
{
class Entry
{
public bool mIsDirectory;
public String mFileName ~ delete _;
}
public PathEditWidget mPathEditWidget;
public String mDirectoryPath = new .() ~ delete _;
public List<Entry> mEntries = new .() ~ DeleteContainerAndItems!(_);
public this()
{
}
protected override void InnerInvoke()
{
var searchStr = scope String();
searchStr.Append(mDirectoryPath);
searchStr.Append("/*");
for (var dirEntry in Directory.Enumerate(searchStr, .Directories | .Files))
{
var entry = new Entry();
entry.mIsDirectory = dirEntry.IsDirectory;
entry.mFileName = new String();
dirEntry.GetFileName(entry.mFileName);
mEntries.Add(entry);
}
if (!mDetachState.HasFlag(.Deatched))
mPathEditWidget.mAutocompleteDirty = true;
}
}
DirectoryTask mDirectoryTask ~ { if (_ != null) _.Detach(); };
bool mAutocompleteDirty;
public String mRelPath ~ delete _;
PathKind mPathKind;
DarkButton mBrowseButton;
public this(PathKind pathKind = .Unknown)
{
mPathKind = pathKind;
if (mPathKind != .Unknown)
{
mBrowseButton = new DarkButton();
mBrowseButton.Label = "...";
AddWidget(mBrowseButton);
mBrowseButton.mOnMouseClick.Add(new (mouseArgs) =>
{
if (mPathKind == .Folder)
{
String path = scope .();
GetText(path);
#if !CLI
FolderBrowserDialog folderDialog = scope .();
folderDialog.SelectedPath = path;
mWidgetWindow.PreModalChild();
if (folderDialog.ShowDialog(gApp.GetActiveWindow()).GetValueOrDefault() == .OK)
{
SetText(scope String()..Append(folderDialog.SelectedPath));
}
#endif
}
});
}
}
public override void UpdateText(char32 keyChar, bool doAutoComplete)
{
if (!doAutoComplete)
return;
var editText = scope String();
GetText(editText);
int cursorPos = mEditWidgetContent.CursorTextPos;
int firstSlash = -1;
int startSlash = -1;
int nextSlash = -1;
for (int i < editText.Length)
{
let c = editText[i];
if ((c == '\\') || (c == '/'))
{
if (firstSlash == -1)
firstSlash = i;
if (cursorPos >= i)
{
startSlash = i;
}
else
{
if (nextSlash == -1)
nextSlash = i;
}
}
}
var editWidgetContent = (ExpressionEditWidgetContent)mEditWidgetContent;
if ((firstSlash != -1) && (keyChar != '\'') && (keyChar != '/'))
{
String selStr = scope String();
if (nextSlash != -1)
selStr.Append(editText, startSlash + 1, nextSlash - startSlash - 1);
else
selStr.Append(editText, startSlash + 1, cursorPos - startSlash - 1);
String info = scope .();
info.Append("uncertain\n");
info.AppendF("insertRange\t{0} {1}\n", startSlash + 1, cursorPos);
//info.Append("directory\thi\n");
//info.Append("directory\thi2\n");
String subRelPath = scope String();
if (startSlash != -1)
subRelPath.Append(editText, 0, startSlash);
var subAbsPath = scope String();
if (mRelPath != null)
Path.GetAbsolutePath(subRelPath, mRelPath, subAbsPath);
else
Path.GetAbsolutePath(subRelPath, gApp.mInstallDir, subAbsPath);
if ((mDirectoryTask == null) || (mDirectoryTask.mDirectoryPath != subAbsPath))
{
if (mDirectoryTask != null)
{
mDirectoryTask.Detach();
mDirectoryTask = null;
}
if (editWidgetContent.mAutoComplete != null)
editWidgetContent.mAutoComplete.Close();
mDirectoryTask = new DirectoryTask();
mDirectoryTask.mPathEditWidget = this;
mDirectoryTask.mDirectoryPath.Set(subAbsPath);
mDirectoryTask.Start();
return;
}
if (!mDirectoryTask.IsCompleted)
{
return;
}
for (var entry in mDirectoryTask.mEntries)
{
if (!entry.mFileName.StartsWith(selStr, .OrdinalIgnoreCase))
continue;
if (entry.mIsDirectory)
info.AppendF("folder\t{0}\n", entry.mFileName);
else
info.AppendF("file\t{0}\n", entry.mFileName);
}
var autoComplete = GetAutoComplete();
autoComplete.mUncertain = true;
SetAutoCompleteInfo(info, 0);
}
else
{
if (mDirectoryTask != null)
{
mDirectoryTask.Detach();
mDirectoryTask = null;
}
if (editWidgetContent.mAutoComplete != null)
editWidgetContent.mAutoComplete.Close();
}
}
public override void Update()
{
base.Update();
if (mAutocompleteDirty)
{
UpdateText(0, true);
mAutocompleteDirty = false;
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
if (mBrowseButton != null)
{
mBrowseButton.Resize(mWidth - DarkTheme.sUnitSize - GS!(2), GS!(2), DarkTheme.sUnitSize, DarkTheme.sUnitSize);
}
}
}
class PathComboBox : DarkComboBox
{
public override bool WantsKeyHandling()
{
if (mEditWidget == null)
return true;
var expressionEditWidget = (ExpressionEditWidgetContent)mEditWidget.mEditWidgetContent;
return expressionEditWidget.mAutoComplete == null;
}
}
}

View file

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy.widgets;
namespace IDE.ui
{
public class PersistentTextPosition
{
public int32 mIndex;
public bool mWasDeleted;
public this(int32 index)
{
mIndex = index;
}
public ~this()
{
}
}
}

109
IDE/src/ui/ProfileDialog.bf Normal file
View file

@ -0,0 +1,109 @@
using System;
using Beefy;
using Beefy.theme.dark;
using Beefy.widgets;
using Beefy.gfx;
namespace IDE.ui
{
class ProfileDialog : IDEDialog
{
EditWidget mDescEdit;
DarkComboBox mThreadCombo;
EditWidget mSampleRateEdit;
public this()
{
mTitle = new String("Profile");
mText = new String("");
mDescEdit = AddEdit("");
mThreadCombo = new DarkComboBox();
mThreadCombo.Label = "All Threads";
mThreadCombo.mPopulateMenuAction.Add(new => PopulateThreadList);
AddDialogComponent(mThreadCombo);
mWindowFlags = BFWindow.Flags.ClientSized | BFWindow.Flags.TopMost | BFWindow.Flags.Caption |
BFWindow.Flags.Border | BFWindow.Flags.SysMenu | BFWindow.Flags.Resizable;
mSampleRateEdit = AddEdit(scope String()..AppendF("{0}", gApp.mSettings.mDebuggerSettings.mProfileSampleRate));
AddOkCancelButtons(new (evt) => { StartProfiling(); }, null, 0, 1);
}
void StartProfiling()
{
var str = scope String();
mThreadCombo.GetLabel(str);
int spacePos = str.IndexOf(' ');
if (spacePos > 0)
str.RemoveToEnd(spacePos);
int threadId = int.Parse(str).GetValueOrDefault();
str.Clear();
mSampleRateEdit.GetText(str);
int sampleRate = int.Parse(str).GetValueOrDefault();
if (sampleRate < 0)
sampleRate = gApp.mSettings.mDebuggerSettings.mProfileSampleRate;
sampleRate = Math.Clamp(sampleRate, 10, 10000);
str.Clear();
mDescEdit.GetText(str);
gApp.mProfilePanel.StartProfiling(threadId, str, sampleRate);
}
void PopulateThreadList(Menu menu)
{
var subItem = menu.AddItem("All Threads");
subItem.mOnMenuItemSelected.Add(new (evt) => { mThreadCombo.Label = "All Threads"; });
String threadInfo = scope .();
gApp.mDebugger.GetThreadInfo(threadInfo);
for (var infoLine in threadInfo.Split('\n'))
{
if (@infoLine.Pos == 0)
continue;
var infoSections = infoLine.Split('\t');
StringView id = infoSections.GetNext().GetValueOrDefault();
StringView name = infoSections.GetNext().GetValueOrDefault();
var str = scope String();
str.AppendF("{0} - {1}", id, name);
subItem = menu.AddItem(str);
subItem.mOnMenuItemSelected.Add(new (item) => { mThreadCombo.Label = item.mLabel; });
}
}
public override void ResizeComponents()
{
base.ResizeComponents();
float curY = GS!(30);
mDescEdit.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
curY += GS!(42);
mThreadCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(24));
curY += GS!(42);
mSampleRateEdit.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(24));
}
public override void Draw(Graphics g)
{
base.Draw(g);
DrawLabel(g, mDescEdit, "Profile Description (Optional)");
DrawLabel(g, mThreadCombo, "Thread");
DrawLabel(g, mSampleRateEdit, "Sample Rate");
}
public override void CalcSize()
{
mWidth = GS!(280);
mHeight = GS!(180);
}
}
}

690
IDE/src/ui/ProfilePanel.bf Normal file
View file

@ -0,0 +1,690 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using Beefy;
using Beefy.widgets;
using Beefy.theme;
using Beefy.gfx;
using Beefy.theme.dark;
using Beefy.events;
using Beefy.utils;
using IDE.Debugger;
namespace IDE.ui
{
class ProfilePanel : Panel
{
class ProfileListViewItem : DarkListViewItem
{
public int32 mSelfSamples;
public int32 mChildSamples;
float ArrowCenterY
{
get
{
return DarkTheme.sUnitSize * 0.5f + GS!(4) + 1;
}
}
protected override void DrawChildren(Graphics g, int itemStart, int itemEnd)
{
base.DrawChildren(g, itemStart, itemEnd);
if (mParentItem == null)
return;
float barWidth = (int)GS!(1.5f);
let lastItem = mChildItems.Back;
if (!lastItem.mVisible)
return;
let parent = (DarkListView)mListView;
float absX = (mDepth - 1) * parent.mChildIndent + GS!(12);
if (absX >= parent.mColumns[0].mWidth)
return;
using (g.PushColor(0xFFB0B0B0))
g.FillRect((int)ArrowCenterY, GS!(14), barWidth, (int)lastItem.mY - (int)GS!(4.8f));
}
public override void DrawAll(Graphics g)
{
float barWidth = (int)GS!(1.5f);
var listView = (DarkListView)mListView;
float xStart = mDepth * listView.mChildIndent - GS!(12);
if (xStart < listView.mColumns[0].mWidth)
{
if ((mVisible) && (mColumnIdx == 0) && (mX > 10))
{
using (g.PushColor(0xFFB0B0B0))
{
float horzWidth = GS!(13) - 3 - barWidth;
if (mOpenButton == null)
horzWidth += GS!(4);
g.FillRect(-mX + (int)(ArrowCenterY + GS!(0.7f)), GS!(9), horzWidth, barWidth);
}
}
}
base.DrawAll(g);
}
}
class ProfileListView : DarkListView
{
public this()
{
//mShowLineGrid = true;
}
protected override ListViewItem CreateListViewItem()
{
return new ProfileListViewItem();
}
protected override void SetScaleData()
{
base.SetScaleData();
mIconX = GS!(4);
mOpenButtonX = GS!(4);
mLabelX = GS!(23);
mChildIndent = GS!(16);
mHiliteOffset = GS!(-2);
}
}
public class SessionComboBox : DarkComboBox
{
public bool mIsRecording;
public override void Draw(Graphics g)
{
base.Draw(g);
}
public override void Update()
{
base.Update();
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
mLabelX = mIsRecording ? GS!(24) : GS!(8);
if (mIsRecording)
g.Draw(DarkTheme.sDarkTheme.GetImage(.RedDot), GS!(4), GS!(0));
}
}
ProfileListView mListView;
public SessionComboBox mSessionComboBox;
public DarkComboBox mThreadComboBox;
DarkButton mStopButton;
public bool mThreadsDirty = true;
public int32 mThreadIdx;
public int32 mDisabledTicks;
public DbgProfiler mProfiler;
public List<int32> mThreadList = new List<int32>() ~ delete _;
public uint32 mTickCreated;
public int32 mCurIdx;
public DbgProfiler mUserProfiler;
public DbgProfiler.Overview mShowOverview ~ delete _;
public int mOverviewAge;
public bool mAwaitingLoad;
public bool mIsSamplingHidden;
public List<DbgProfiler> mProfilers = new List<DbgProfiler>() ~ DeleteContainerAndItems!(_);
const String cStartProfilingCmd = " < Start Profiling > ";
const String cStartProfilingExCmd = " < Profile... > ";
public bool IsSamplingHidden
{
get
{
return mIsSamplingHidden;
}
}
public this()
{
mSessionComboBox = new SessionComboBox();
mSessionComboBox.mPopulateMenuAction.Add(new => PopulateSessionList);
AddWidget(mSessionComboBox);
mSessionComboBox.Label = cStartProfilingCmd;
mTabWidgets.Add(mSessionComboBox);
mStopButton = new DarkButton();
mStopButton.Label = "Stop";
AddWidget(mStopButton);
mStopButton.mOnMouseClick.Add(new (evt) =>
{
if (mProfiler != null)
mProfiler.Stop();
});
mThreadComboBox = new DarkComboBox();
mThreadComboBox.mPopulateMenuAction.Add(new => PopulateThreadList);
AddWidget(mThreadComboBox);
mTabWidgets.Add(mThreadComboBox);
mListView = new ProfileListView();
mListView.InitScrollbars(true, true);
mListView.mHorzScrollbar.mPageSize = GS!(100);
mListView.mHorzScrollbar.mContentSize = GS!(500);
mListView.mVertScrollbar.mPageSize = GS!(100);
mListView.mVertScrollbar.mContentSize = GS!(500);
mListView.UpdateScrollbars();
mListView.mOnMouseDown.Add(new (mouseArgs) =>
{
SetFocus();
});
mListView.mOnItemMouseDown.Add(new => ValueMouseDown);
mTabWidgets.Add(mListView);
//mListView.mDragEndHandler += HandleDragEnd;
//mListView.mDragUpdateHandler += HandleDragUpdate;
AddWidget(mListView);
//mListView.mMouseDownHandler += ListViewMouseDown;
ListViewColumn column = mListView.AddColumn(300, "Function");
column.mMinWidth = 100;
column = mListView.AddColumn(80, "Total CPU %");
column.mMinWidth = 60;
column = mListView.AddColumn(80, "Self CPU %");
column.mMinWidth = 60;
column = mListView.AddColumn(90, "Total CPU (ms)");
column.mMinWidth = 60;
column = mListView.AddColumn(90, "Self CPU (ms)");
column.mMinWidth = 60;
//RebuildUI();
}
public void Clear()
{
mUserProfiler = null;
mProfiler = null;
ClearAndDeleteItems(mProfilers);
mSessionComboBox.Label = cStartProfilingCmd;
mThreadComboBox.Label = "";
mListView.GetRoot().Clear();
mThreadList.Clear();
DeleteAndNullify!(mShowOverview);
mAwaitingLoad = false;
}
public void StartProfiling(int threadId, String desc, int sampleRate)
{
if (mUserProfiler != null)
return;
if (!gApp.mDebugger.mIsRunning)
{
gApp.RunWithCompiling();
gApp.QueueProfiling(threadId, desc, sampleRate);
return;
}
mUserProfiler = gApp.mDebugger.StartProfiling(threadId, desc, sampleRate);
mUserProfiler.mIsManual = true;
Add(mUserProfiler);
Show(mUserProfiler);
}
public void StartProfiling()
{
StartProfiling(0, "", gApp.mSettings.mDebuggerSettings.mProfileSampleRate);
}
public void StopProfiling()
{
if (mUserProfiler == null)
return;
mUserProfiler.Stop();
mUserProfiler = null;
}
void PopulateSessionList(Menu menu)
{
var item = menu.AddItem(cStartProfilingCmd);
item.mOnMenuItemSelected.Add(new (item) =>
{
StartProfiling();
});
item = menu.AddItem(cStartProfilingExCmd);
item.mOnMenuItemSelected.Add(new (item) =>
{
var profileDialog = new ProfileDialog();
profileDialog.PopupWindow(mWidgetWindow);
//StartProfilingEx();
});
for (int profilerIdx = mProfilers.Count - 1; profilerIdx >= 0; profilerIdx--)
{
var profiler = mProfilers[profilerIdx];
var label = scope String();
profiler.GetLabel(label);
item = menu.AddItem(label);
var overview = scope DbgProfiler.Overview();
profiler.GetOverview(overview);
if (overview.IsSampling)
item.mIconImage = DarkTheme.sDarkTheme.GetImage(.RedDot);
item.mOnMenuItemSelected.Add(new (item) =>
{
mSessionComboBox.Label = item.mLabel;
Show(profiler);
});
}
}
void PopulateThreadList(Menu menu)
{
if (mProfiler == null)
return;
var subItem = menu.AddItem("All Threads");
subItem.mOnMenuItemSelected.Add(new (item) => { Show(0, .()); });
var threadListStr = scope String();
mProfiler.GetThreadList(threadListStr);
for (var entry in threadListStr.Split('\n'))
{
if (entry.Length == 0)
continue;
var dataItr = entry.Split('\t');
int32 threadId = int32.Parse(dataItr.GetNext());
StringView threadName = dataItr.GetNext();
String threadStr = null;
var str = scope String();
str.AppendF("{0}", threadId);
if (!threadName.IsEmpty)
{
threadStr = new String(threadName);
str.AppendF(" - {0}", threadName);
}
subItem = menu.AddItem(str);
subItem.mOnMenuItemSelected.Add(new (item) => { Show(threadId, threadStr); } ~ delete threadStr);
}
}
public void Show(int32 threadId, StringView threadName)
{
mTickCreated = Utils.GetTickCount();
if (threadId == 0)
mThreadComboBox.Label = "All Threads";
else
{
var threadStr = scope String();
threadStr.AppendF("{0}", threadId);
if (!threadName.IsEmpty)
threadStr.AppendF(" - {0}", threadName);
mThreadComboBox.Label = threadStr;
}
mThreadList.Clear();
var str = scope String();
mProfiler.GetCallTree(threadId, str, false);
List<DarkListViewItem> itemStack = scope List<DarkListViewItem>();
DarkListViewItem curItem = (DarkListViewItem)mListView.GetRoot();
mListView.GetRoot().Clear();
var overview = scope DbgProfiler.Overview();
mProfiler.GetOverview(overview);
int32 totalSamples = 0;
float sampleTimeMult = 1000.0f / overview.mSamplesPerSecond; // 1ms per sample
for (var lineView in str.Split('\n'))
{
var line = scope String(lineView);
if (line.Length == 0)
continue;
if (line == "-")
{
curItem = itemStack.PopBack();
curItem.mChildItems.Sort(scope (baseA, baseB) =>
{
var a = (ProfileListViewItem)baseA;
var b = (ProfileListViewItem)baseB;
return (b.mChildSamples + b.mSelfSamples) - (a.mChildSamples + a.mSelfSamples);
});
continue;
}
var dataList = scope List<StringView>(line.Split('\t'));
ProfileListViewItem newItem = (ProfileListViewItem)curItem.CreateChildItem();
newItem.mLabel = new String(dataList[0]);
//newItem.mOnMouseDown.Add(new => ValueClicked);
var selfStr = scope String(dataList[1]);
var childStr = scope String(dataList[2]);
newItem.mSelfSamples = int32.Parse(selfStr);
newItem.mChildSamples = int32.Parse(childStr);
if (totalSamples == 0)
totalSamples = newItem.mChildSamples;
var subItem = newItem.CreateSubItem(1);
var tempStr = scope String();
if (totalSamples == 0)
tempStr.Append("0.00%");
else
tempStr.AppendF("{0:0.00}%", (newItem.mSelfSamples + newItem.mChildSamples) * 100.0f / totalSamples);
subItem.Label = tempStr;
//subItem.mOnMouseDown.Add(new => ValueClicked);
subItem = newItem.CreateSubItem(2);
tempStr.Clear();
if (totalSamples == 0)
tempStr.Append("0.00%");
else
tempStr.AppendF("{0:0.00}%", newItem.mSelfSamples * 100.0f / totalSamples);
subItem.Label = tempStr;
//subItem.mOnMouseDown.Add(new => ValueClicked);
subItem = newItem.CreateSubItem(3);
tempStr.Clear();
tempStr.AppendF("{0}ms", (int32)((newItem.mSelfSamples + newItem.mChildSamples) * sampleTimeMult + 0.5f));
subItem.Label = tempStr;
//subItem.mOnMouseDown.Add(new => ValueClicked);
subItem = newItem.CreateSubItem(4);
tempStr.Clear();
tempStr.AppendF("{0}ms", (int32)(newItem.mSelfSamples * sampleTimeMult + 0.5f));
subItem.Label = tempStr;
//subItem.mOnMouseDown.Add(new => ValueClicked);
itemStack.Add(curItem);
curItem = newItem;
}
}
public void Add(DbgProfiler profiler)
{
profiler.mIdx = mCurIdx++;
mProfilers.Add(profiler);
}
public void UpdateOverview(out bool changed)
{
changed = false;
int prevActualSamples = (mShowOverview?.mTotalActualSamples).GetValueOrDefault();
DeleteAndNullify!(mShowOverview);
if (mProfiler == null)
return;
mShowOverview = new DbgProfiler.Overview();
mProfiler.GetOverview(mShowOverview);
changed = mShowOverview.mTotalActualSamples != prevActualSamples;
mOverviewAge = 0;
}
public void Show(DbgProfiler profiler)
{
mThreadList.Clear();
mProfiler = profiler;
UpdateOverview(var changed);
var overview = scope DbgProfiler.Overview();
profiler.GetOverview(overview);
var label = scope String();
profiler.GetLabel(label);
mSessionComboBox.Label = label;
if (overview.IsSampling)
{
mAwaitingLoad = true;
mThreadComboBox.Label = "";
mListView.GetRoot().Clear();
ResizeComponents();
return;
}
mAwaitingLoad = false;
var threadListStr = scope String();
mProfiler.GetThreadList(threadListStr);
for (var entry in threadListStr.Split('\n'))
{
if (entry.Length == 0)
continue;
var dataItr = entry.Split('\t');
int32 threadId = int32.Parse(dataItr.GetNext());
mThreadList.Add(threadId);
}
if (mThreadList.Count == 0)
return;
int32 threadId = mThreadList[0];
Show(threadId, .());
ResizeComponents();
}
public override void Serialize(StructuredData data)
{
base.Serialize(data);
data.Add("Type", "ProfilePanel");
}
public override bool Deserialize(StructuredData data)
{
return base.Deserialize(data);
}
void ValueMouseDown(ListViewItem item, float x, float y, int32 btnNum, int32 btnCount)
{
#unwarn
DarkListViewItem baseItem = (DarkListViewItem)item.GetSubItem(0);
ListViewItemMouseDown(item, x, y, btnNum, btnCount);
if ((btnNum == 0) && (btnCount > 1))
{
/*for (int childIdx = 0; childIdx < mListView.GetRoot().GetChildCount(); childIdx++)
{
var checkListViewItem = mListView.GetRoot().GetChildAtIndex(childIdx);
checkListViewItem.IconImage = null;
}
int selectedIdx = mListView.GetRoot().GetIndexOfChild(item);
int threadId = int.Parse(item.mLabel);
IDEApp.sApp.mDebugger.SetActiveThread(threadId);
IDEApp.sApp.mDebugger.mCallStackDirty = true;
IDEApp.sApp.mCallStackPanel.MarkCallStackDirty();
IDEApp.sApp.mCallStackPanel.Update();
IDEApp.sApp.mWatchPanel.MarkWatchesDirty(true);
IDEApp.sApp.mAutoWatchPanel.MarkWatchesDirty(true);
IDEApp.sApp.mMemoryPanel.MarkViewDirty();
IDEApp.sApp.ShowPCLocation(IDEApp.sApp.mDebugger.mSelectedCallStackIdx, false, true);
item.IconImage = DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.ArrowRight);*/
}
}
void ResizeComponents()
{
mThreadComboBox.Resize(GS!(80), GS!(22), GS!(220), GS!(24));
mListView.Resize(0, GS!(44), mWidth, Math.Max(mHeight - GS!(44), 0));
if (mSessionComboBox.mIsRecording)
{
mStopButton.mVisible = true;
mStopButton.Resize(GS!(28), GS!(1), GS!(52), GS!(22));
//mSessionComboBox.Resize(GS!(80) + GS!(42), GS!(1), GS!(220) - GS!(42), GS!(24));
mSessionComboBox.Resize(GS!(80), GS!(1), GS!(220), GS!(24));
}
else
{
mStopButton.mVisible = false;
mSessionComboBox.Resize(GS!(80), GS!(1), GS!(220), GS!(24));
}
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
public void MarkThreadsDirty()
{
mThreadsDirty = true;
}
public override void LostFocus()
{
base.LostFocus();
mListView.GetRoot().SelectItemExclusively(null);
}
public override void Update()
{
base.Update();
if (mUserProfiler != null)
{
if (!mUserProfiler.IsSampling)
mUserProfiler = null;
}
if (mProfiler == null)
{
if (!mProfilers.IsEmpty)
{
var profiler = mProfilers.Back;
Show(profiler);
MarkDirty();
}
}
if (mProfiler != null)
{
++mOverviewAge;
if (mOverviewAge >= 15)
{
UpdateOverview(var changed);
if (changed)
MarkDirty();
}
if (mUpdateCnt % 60 == 0)
MarkDirty();
if ((!mProfiler.IsSampling) && (mAwaitingLoad))
Show(mProfiler);
}
if (mShowOverview != null)
mSessionComboBox.mIsRecording = mShowOverview.IsSampling;
else
mSessionComboBox.mIsRecording = false;
ResizeComponents();
}
public void ForcedUpdate()
{
bool isSamplingHidden = false;
if ((mWidgetWindow == null) || (mProfiler == null) || (!mProfiler.IsSampling))
{
for (var profile in mProfilers)
if (profile.IsSampling)
isSamplingHidden = true;
}
if (mIsSamplingHidden != isSamplingHidden)
{
mIsSamplingHidden = isSamplingHidden;
gApp.MarkDirty();
}
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
}
public override void Draw(Graphics g)
{
base.Draw(g);
g.SetFont(DarkTheme.sDarkTheme.mSmallFont);
g.DrawString("Session", mSessionComboBox.mX - GS!(2), mSessionComboBox.mY, .Right);
g.DrawString("Thread", mThreadComboBox.mX - GS!(2), mThreadComboBox.mY, .Right);
if ((mProfiler != null) && (mShowOverview != null))
{
g.DrawString(StackStringFormat!("Rate: {0} Hz", mShowOverview.mSamplesPerSecond), GS!(320), GS!(2));
int32 seconds = (mShowOverview.mRecordedTicks / 1000);
g.DrawString(StackStringFormat!("Length: {0}:{1:02}.{2}", seconds / 60, seconds % 60, (mShowOverview.mRecordedTicks % 1000)/100), GS!(320), GS!(22));
seconds = (mShowOverview.mEndedTicks / 1000);
if (seconds > 60*60)
g.DrawString(StackStringFormat!("Age: {0}:{1:02}:{2:02}", seconds / 60 / 60, (seconds / 60) % 60, seconds % 60), GS!(420), GS!(22));
else
g.DrawString(StackStringFormat!("Age: {0}:{1:02}", seconds / 60, seconds % 60), GS!(420), GS!(22));
g.DrawString(StackStringFormat!("Samples: {0}", mShowOverview.mTotalActualSamples), GS!(420), GS!(2));
g.DrawString(StackStringFormat!("Missed Samples: {0}", mShowOverview.mTotalVirtualSamples - mShowOverview.mTotalActualSamples), GS!(550), GS!(2));
}
if (mTickCreated != 0)
{
/*String text = scope String();
text.AppendF("{0}s ago", (int32)(Utils.GetTickCount() - mTickCreated) / 1000);
g.DrawString(text, mWidth - 4, 2, FontAlign.Right);*/
}
}
public override void FocusForKeyboard()
{
base.FocusForKeyboard();
mSessionComboBox.SetFocus();
}
public override void MouseDown(float x, float y, int32 btn, int32 btnCount)
{
base.MouseDown(x, y, btn, btnCount);
SetFocus();
}
}
}

2199
IDE/src/ui/ProjectPanel.bf Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Beefy.gfx;
using Beefy.theme;
using Beefy.theme.dark;
using Beefy.widgets;
using Beefy.events;
using Beefy;
using Beefy.utils;
//using System.Windows.Forms;
namespace IDE.ui
{
public class PropertiesPanel : Panel
{
public override void Serialize(StructuredData data)
{
base.Serialize(data);
data.Add("Type", "PropertiesPanel");
}
public override bool Deserialize(StructuredData data)
{
return base.Deserialize(data);
}
}
}

725
IDE/src/ui/QuickFind.bf Normal file
View file

@ -0,0 +1,725 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.widgets;
using Beefy.theme;
using Beefy.theme.dark;
using Beefy.events;
using Beefy.utils;
using IDE.ui;
using System.Diagnostics;
namespace IDE.ui
{
public class QuickFind : Widget
{
enum FindType
{
CurrentFile,
Selection,
}
public class FindEdit : DarkEditWidget
{
QuickFind mQuickFind;
int32 mFoundVersion;
public this(QuickFind quickFind)
{
mQuickFind = quickFind;
}
public override void KeyDown(KeyCode keyCode, bool isRepeat)
{
if (keyCode == KeyCode.Escape)
{
mQuickFind.Close();
return;
}
base.KeyDown(keyCode, isRepeat);
}
public override void KeyChar(char32 theChar)
{
/*if ((theChar == '\r') || (theChar == '\n'))
{
mQuickFind.FindNext();
return;
} */
if (theChar == '\t')
return;
base.KeyChar(theChar);
}
public override void Update()
{
base.Update();
if (Content.mData.mCurTextVersionId != mFoundVersion)
{
mFoundVersion = Content.mData.mCurTextVersionId;
mQuickFind.mCurFindIdx = -1;
mQuickFind.FindAll();
mQuickFind.ShowCurrentSelection();
}
}
}
public TextPanel mPanel;
public EditWidget mEditWidget;
public EditWidget mFindEditWidget;
public EditWidget mReplaceEditWidget;
public int32 mLastActiveCursorPos;
bool mHasNewActiveCursorPos;
public int32 mCurFindIdx = -1;
public int32 mCurFindStart = 0;
public int32 mCurFindCount;
//public bool mSearchDidWrap;
public bool mIsReplace;
public int32 mLastTextVersion;
bool mFoundMatches;
bool mIsShowingMatches = false;
static String sLastSearchString = new String() ~ delete _;
public bool mOwnsSelection;
PersistentTextPosition mSelectionStart ~ { Debug.Assert(_ == null); };
PersistentTextPosition mSelectionEnd ~ { Debug.Assert(_ == null); };
public this(Widget parent, EditWidget editWidget, bool isReplace)
{
mPanel = parent as TextPanel;
mEditWidget = editWidget;
parent.AddWidget(this);
mIsReplace = isReplace;
UpdateCursorPos();
mFindEditWidget = new FindEdit(this);
mFindEditWidget.Content.SelectAll();
mFindEditWidget.mOnKeyDown.Add(new => KeyDownHandler);
AddWidget(mFindEditWidget);
if (isReplace)
{
mReplaceEditWidget = new FindEdit(this);
mReplaceEditWidget.mOnKeyDown.Add(new => KeyDownHandler);
AddWidget(mReplaceEditWidget);
}
mLastTextVersion = mEditWidget.Content.mData.mCurTextVersionId;
var content = editWidget.Content;
var sourceContent = editWidget.Content as SourceEditWidgetContent;
if (content.HasSelection())
{
int selStart = content.mSelection.Value.MinPos;
int selEnd = content.mSelection.Value.MaxPos;
bool isMultiline = false;
for (int i = selStart; i < selEnd; i++)
{
if (content.mData.mText[i].mChar == '\n')
{
isMultiline = true;
break;
}
}
if (isMultiline)
{
Debug.Assert(mSelectionStart == null);
mSelectionStart = new PersistentTextPosition((int32)selStart);
mSelectionEnd = new PersistentTextPosition((int32)selEnd);
if (sourceContent != null)
{
sourceContent.PersistentTextPositions.Add(mSelectionStart);
sourceContent.PersistentTextPositions.Add(mSelectionEnd);
}
else
mOwnsSelection = true;
}
else
{
String text = scope String();
content.ExtractString(selStart, selEnd - selStart, text);
text.Trim();
mFindEditWidget.SetText(text);
mFindEditWidget.Content.SelectAll();
}
}
}
public ~this()
{
}
void UpdateCursorPos()
{
if (mEditWidget.mHasFocus)
{
mHasNewActiveCursorPos = true;
mLastActiveCursorPos = (int32)mEditWidget.Content.CursorTextPos;
if (mEditWidget.Content.HasSelection())
mLastActiveCursorPos = (int32)mEditWidget.Content.mSelection.Value.MinPos;
}
}
void DoReplace(bool all)
{
int32 replaceCount = -1;
if (all)
{
mEditWidget.SetFocus();
replaceCount = Replace();
if (replaceCount > 0)
IDEApp.sApp.MessageDialog("Replace Results", StackStringFormat!("{0} instance(s) replaced.", replaceCount));
}
else
{
//replaceCount = Replace((byte)SourceElementFlags.Find_CurrentSelection);
var content = mEditWidget.Content;
String replaceText = scope String();
mReplaceEditWidget.GetText(replaceText);
bool hasMatch = false;
if (content.HasSelection())
{
String selText = scope String();
content.GetSelectionText(selText);
String findText = scope String();
mFindEditWidget.GetText(findText);
if (selText == findText)
hasMatch = true;
}
if (hasMatch)
{
content.InsertAtCursor(replaceText);
mCurFindIdx = (int32)content.CursorTextPos - 1;
}
FindNext(1, false);
}
if (replaceCount != -1)
{
if (replaceCount == 0)
IDEApp.sApp.Fail("The search text wasn't found.");
mWidgetWindow.mIsKeyDownHandled = true;
}
}
void KeyDownHandler(KeyDownEvent evt)
{
if (evt.mKeyCode == KeyCode.Escape)
Close();
if (evt.mKeyCode == KeyCode.Return)
{
if (evt.mSender == mFindEditWidget)
{
FindNext(1, true);
}
else if (evt.mSender == mReplaceEditWidget)
{
DoReplace(false);
}
}
if (evt.mKeyCode == KeyCode.Tab)
{
IDEUtils.SelectNextChildWidget(this, mWidgetWindow.IsKeyDown(KeyCode.Shift));
}
//int replaceCount = -1;
if ((evt.mKeyCode == (KeyCode)'R') && (mWidgetWindow.IsKeyDown(KeyCode.Menu)))
DoReplace(false);
if ((evt.mKeyCode == (KeyCode)'A') && (mWidgetWindow.IsKeyDown(KeyCode.Menu)))
DoReplace(true);
}
void EditWidgetSubmit(EditEvent editEvent)
{
//FindNext(true);
}
public bool ClearFlags(bool clearMatches, bool clearSelection)
{
uint8 mask = 0xFF;
if (clearMatches)
mask = (uint8)(mask & ~(uint8)SourceElementFlags.Find_Matches);
//if (clearSelection)
//mask = (byte)(mask & ~(byte)SourceElementFlags.Find_CurrentSelection);
bool foundFlags = false;
var text = mEditWidget.Content.mData.mText;
for (int32 i = 0; i < text.Count; i++)
{
if ((text[i].mDisplayFlags & ~mask) != 0)
{
text[i].mDisplayFlags = (uint8)(text[i].mDisplayFlags & mask);
foundFlags = true;
}
}
return foundFlags;
}
public void FindAll()
{
mIsShowingMatches = true;
mFoundMatches = false;
mCurFindStart = mLastActiveCursorPos;
mCurFindIdx = mCurFindStart - 1;
mCurFindCount = 0;
//mSearchDidWrap = false;
ClearFlags(true, true);
FindNext(1, true, ErrorReportType.None);
int32 curFindIdx = mCurFindIdx;
while (FindNext(1, false, ErrorReportType.None))
{
}
mCurFindIdx = curFindIdx;
mCurFindCount = 0;
}
public void ShowCurrentSelection()
{
if (mCurFindIdx == -1)
return;
String findText = scope String();
mFindEditWidget.GetText(findText);
if (findText.Length == 0)
return;
var editWidgetContent = mEditWidget.Content;
editWidgetContent.MoveCursorToIdx(mCurFindIdx + (int32)findText.Length, true);
if ((mSelectionStart == null) || (mParent == null))
{
if (mFoundMatches)
editWidgetContent.mSelection = EditSelection(mCurFindIdx, mCurFindIdx + (int32)findText.Length);
else if (!String.IsNullOrWhiteSpace(findText))
editWidgetContent.mSelection = null;
}
if (mHasNewActiveCursorPos)
{
if (mPanel != null)
mPanel.RecordHistoryLocation();
mHasNewActiveCursorPos = false;
}
}
public void FindNext(int32 dir, bool showMessage)
{
var editWidgetContent = mEditWidget.Content;
if (!mIsShowingMatches)
{
// This only happens after we close the quickfind and we need to reshow the matches
if (sLastSearchString.Length > 0)
mFindEditWidget.SetText(sLastSearchString);
mCurFindIdx = (int32)editWidgetContent.CursorTextPos;
int32 curFindIdx = mCurFindIdx;
FindAll();
mCurFindIdx = curFindIdx;
}
if (!mFoundMatches)
{
IDEApp.sApp.Fail("The search text wasn't found.");
return;
}
ClearFlags(false, true);
if (FindNext(dir, true, showMessage ? ErrorReportType.MessageBox : ErrorReportType.Sound))
ShowCurrentSelection();
}
public enum ErrorReportType
{
None,
Sound,
MessageBox
}
void ShowDoneError(ErrorReportType errorType)
{
if (errorType != ErrorReportType.None)
{
IDEApp.Beep(IDEApp.MessageBeepType.Information);
if (errorType == ErrorReportType.MessageBox)
IDEApp.sApp.MessageDialog("Search Done", "Find reached the starting point of the search.");
}
}
public bool FindNext(int32 dir, bool isSelection, ErrorReportType errorType)
{
var editContent = mEditWidget.Content;
String findText = scope String();
mFindEditWidget.GetText(findText);
sLastSearchString.Set(findText);
if (findText.Length == 0)
return false;
String findTextLower = scope String(findText);
findTextLower.ToLower();
String findTextUpper = scope String(findText);
findTextUpper.ToUpper();
if ((mCurFindIdx == -1) && (mSelectionStart != null))
{
mCurFindIdx = mSelectionStart.mIndex - 1;
}
int32 selStart = (mSelectionStart != null) ? mSelectionStart.mIndex : 0;
int32 selEnd = (mSelectionEnd != null) ? mSelectionEnd.mIndex : editContent.mData.mTextLength;
mCurFindStart = Math.Max(mCurFindStart, selStart);
int32 nextIdx = -1;
int32 searchStartIdx;
if (dir < 0)
{
if (mCurFindIdx == -1)
searchStartIdx = selEnd + dir - (int32)findText.Length;
else
searchStartIdx = mCurFindIdx + dir;
if (searchStartIdx < selStart)
searchStartIdx = selStart;
}
else
{
searchStartIdx = mCurFindIdx + dir;
if (searchStartIdx < selStart)
searchStartIdx = selStart;
}
/*if ((searchStartIdx == mCurFindStart) && (mCurFindCount > 0))
{
mCurFindCount = 0;
return false;
}*/
//for (int startIdx = searchStartIdx; startIdx <= selEnd - findText.Length; startIdx++)
for (int32 startIdx = searchStartIdx; true; startIdx += dir)
{
if (startIdx > selEnd - findText.Length)
break;
if (startIdx < 0)
break;
bool isEqual = true;
for (int32 i = 0; i < findText.Length; i++)
{
if ((editContent.mData.mText[i + startIdx].mChar != findTextLower[i]) &&
(editContent.mData.mText[i + startIdx].mChar != findTextUpper[i]))
{
isEqual = false;
break;
}
}
if (isEqual)
{
nextIdx = startIdx;
break;
}
}
/*if (nextIdx == mCurFindIdx - 1)
{
int a = 0;
}*/
if (dir < 0)
{
int32 checkOfs = (mCurFindCount == 0) ? 1 : 0;
if ((searchStartIdx >= mCurFindStart + checkOfs) && ((nextIdx == -1) || (nextIdx <= mCurFindStart)))
{
if (isSelection)
ShowDoneError(errorType);
mCurFindIdx = mCurFindStart - 1;
mCurFindCount = 0;
return false;
}
}
else
{
int32 checkOfs = (mCurFindCount == 0) ? -1 : 0;
if ((searchStartIdx <= mCurFindStart + checkOfs) && ((nextIdx == -1) || (nextIdx >= mCurFindStart)))
{
if (isSelection)
ShowDoneError(errorType);
mCurFindIdx = mCurFindStart - 1;
mCurFindCount = 0;
return false;
}
}
/*if ((mSelectionEnd != null) && (nextIdx + findText.Length > mSelectionEnd.mIndex))
return false;*/
//nextIdx = -1;
if (nextIdx != -1)
{
mCurFindCount++;
mFoundMatches = true;
for (int32 idx = nextIdx; idx < nextIdx + findText.Length; idx++)
{
uint8 flags = (uint8)SourceElementFlags.Find_Matches;
//if (isSelection)
//flags |= (byte)SourceElementFlags.Find_CurrentSelection;
mEditWidget.Content.mData.mText[idx].mDisplayFlags = (uint8)(mEditWidget.Content.mData.mText[idx].mDisplayFlags | flags);
}
mCurFindIdx = nextIdx;
return true;
}
else
{
//if (isSelection)
{
//if (doError)
//IDEApp.MessageBeep(IDEApp.MessageBeepType.Information);
//return false;
}
}
mCurFindIdx = -1;
if (mCurFindStart == selStart)
{
// Special case for searching from start
if (isSelection)
{
ShowDoneError(errorType);
mCurFindCount = 0;
}
return false;
}
mCurFindIdx = -1;
sReentryCount++;
if (sReentryCount > 10)
{
Runtime.FatalError("Too many iterations!");
}
var result = FindNext(dir, isSelection, errorType);
sReentryCount--;
return result;
}
static int32 sReentryCount;
public int32 Replace()
{
scope AutoBeefPerf("QuickFind.Replace");
int32 searchCount = 0;
int32 searchStart = 0;
String findText = scope String();
mFindEditWidget.GetText(findText);
String replaceText = scope String();
mReplaceEditWidget.GetText(replaceText);
UndoBatchStart undoBatchStart = null;
var ewc = mEditWidget.Content;
//Profiler.StartSampling();
while (true)
{
int32 selEnd = -1;
int32 selStart = -1;
var text = mEditWidget.Content.mData.mText;
for (int32 i = searchStart; i < mEditWidget.Content.mData.mTextLength; i++)
{
if ((text[i].mDisplayFlags & (uint8)SourceElementFlags.Find_Matches) != 0)
{
if (selStart == -1)
selStart = i;
selEnd = i;
}
else if (selEnd != -1)
break;
}
if (selStart == -1)
break;
int32 selLen = selEnd - selStart + 1;
Debug.Assert(selLen % findText.Length == 0);
selEnd = selStart + (int32)findText.Length - 1;
if (searchCount == 0)
{
undoBatchStart = new UndoBatchStart("replace");
ewc.mData.mUndoManager.Add(undoBatchStart);
}
EditSelection selection = EditSelection();
selection.mStartPos = selStart;
selection.mEndPos = selEnd + 1;
ewc.mSelection = selection;
EditWidgetContent.InsertFlags insertFlags = .NoMoveCursor | .NoRestoreSelectionOnUndo | .IsGroupPart;
if (searchCount == 0)
insertFlags |= .IsGroupStart;
ewc.InsertAtCursor(replaceText, insertFlags);
searchStart = selStart + (int32)replaceText.Length;
searchCount++;
/*if (flags == (byte)SourceElementFlags.Find_CurrentSelection)
{
mLastTextVersion = mEditWidget.Content.mCurTextVersionId;
mCurFindIdx = searchStart;
FindNext(true, ErrorReportType.MessageBox);
break;
}*/
}
//Profiler.StopSampling();
if (undoBatchStart != null)
ewc.mData.mUndoManager.Add(undoBatchStart.mBatchEnd);
return searchCount;
}
public void UpdateData()
{
if (mLastTextVersion != mEditWidget.Content.mData.mCurTextVersionId)
{
if (mIsShowingMatches)
FindAll();
mLastTextVersion = mEditWidget.Content.mData.mCurTextVersionId;
}
UpdateCursorPos();
}
public override void Draw(Beefy.gfx.Graphics g)
{
base.Draw(g);
using (g.PushColor(0xFFFFFFFF))
g.DrawBox(DarkTheme.sDarkTheme.GetImage(DarkTheme.ImageIdx.Menu), 0, 0, mWidth - GS!(8), mHeight - GS!(8));
}
public override void DrawAll(Beefy.gfx.Graphics g)
{
base.DrawAll(g);
var findText = scope String();
mFindEditWidget.GetText(findText);
var replaceText = scope String();
if (mReplaceEditWidget != null)
mReplaceEditWidget.GetText(replaceText);
if ((!mFoundMatches) && (!String.IsNullOrWhiteSpace(findText)))
{
using (g.PushColor(0xFFFF0000))
g.OutlineRect(mFindEditWidget.mX, mFindEditWidget.mY, mFindEditWidget.mWidth, mFindEditWidget.mHeight);
}
if ((!mFindEditWidget.mHasFocus) && (findText.Length == 0))
{
using (g.PushColor(0xFF606060))
g.DrawString("Find...", mFindEditWidget.mX + GS!(4), mFindEditWidget.mY);
}
if ((mReplaceEditWidget != null) && (!mReplaceEditWidget.mHasFocus) && (replaceText.Length == 0))
{
using (g.PushColor(0xFF606060))
g.DrawString("Replace...", mReplaceEditWidget.mX + 4, mReplaceEditWidget.mY);
}
using (g.PushColor(0xFF000000))
{
g.DrawString((mSelectionStart != null) ? "Selection" : "Current Document", GS!(6), mHeight - GS!(30));
}
}
// We leave a pointer to this in the TextPanel after we close it so we can still use F3 after its closed
public bool Close()
{
bool didSomething = false;
var sourceContent = mEditWidget.Content as SourceEditWidgetContent;
if (mSelectionStart != null)
{
if (sourceContent != null)
sourceContent.PersistentTextPositions.Remove(mSelectionStart);
DeleteAndNullify!(mSelectionStart);
}
if (mSelectionEnd != null)
{
if (sourceContent != null)
sourceContent.PersistentTextPositions.Remove(mSelectionEnd);
DeleteAndNullify!(mSelectionEnd);
}
mIsShowingMatches = false;
didSomething |= ClearFlags(true, true);
if (mWidgetWindow != null)
{
bool hadFocus = (mWidgetWindow.mFocusWidget != null) && (mWidgetWindow.mFocusWidget.HasParent(this));
didSomething = true;
if (hadFocus)
mWidgetWindow.SetFocus(mEditWidget);
RemoveSelf();
}
return didSomething;
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
mFindEditWidget.Resize(GS!(6), GS!(6), width - GS!(20), GS!(22));
if (mReplaceEditWidget != null)
mReplaceEditWidget.Resize(GS!(6), GS!(6 + 22 + 4), width - GS!(20), GS!(22));
}
public void ResizeSelf()
{
if (mParent == null)
return;
float findWidth = GS!(200);
float findHeight = mIsReplace ? GS!(80) : GS!(56);
var editWidget = mEditWidget;
float x = mParent.mWidth - findWidth;
if (mEditWidget.mVertScrollbar != null)
x -= GS!(10);
Resize(x, editWidget.mY + 2, findWidth, findHeight);
}
public bool HasFocus()
{
if (mHasFocus)
return true;
if (mFindEditWidget.mHasFocus)
return true;
if ((mReplaceEditWidget != null) && (mReplaceEditWidget.mHasFocus))
return true;
return false;
}
}
}

View file

@ -0,0 +1,72 @@
using Beefy.theme.dark;
using System;
using Beefy.events;
namespace IDE.ui
{
class QuickWatchDialog : IDEDialog
{
WatchPanel mWatchPanel;
public void Init(StringView initStr)
{
mWatchPanel = new WatchPanel(false);
AddWidget(mWatchPanel);
Title = "Quick Watch";
mWindowFlags = .ClientSized | .TopMost | .Caption | .Border | .SysMenu | .Resizable;
mWatchPanel.[Friend]mDisabled = gApp.mWatchPanel.[Friend]mDisabled;
mWatchPanel.Update();
mWatchPanel.mOnKeyDown.Add(new => OnKeyDown);
if (!initStr.IsEmpty)
{
mWatchPanel.AddWatchItem(scope String(initStr));
}
}
public override void AddedToParent()
{
base.AddedToParent();
mWatchPanel.SetFocus();
var lvItem = (WatchListViewItem)mWatchPanel.mListView.GetRoot().GetChildAtIndex(0);
if ((lvItem.mWatchEntry != null) && (!lvItem.mWatchEntry.mEvalStr.IsEmpty))
{
mWatchPanel.mListView.GetRoot().GetChildAtIndex(0).Focused = true;
}
else
{
if (!mWatchPanel.[Friend]mDisabled)
mWatchPanel.EditListViewItem(lvItem);
}
}
public override void ResizeComponents()
{
base.ResizeComponents();
mWatchPanel.Resize(mX + GS!(4), mY + GS!(4), mWidth - GS!(4)*2, mHeight - GS!(4)*2);
}
public override void CalcSize()
{
mWidth = GS!(600);
mHeight = GS!(380);
}
void OnKeyDown(KeyDownEvent evt)
{
if (evt.mKeyCode == .Escape)
{
evt.mHandled = true;
Close();
}
}
public override void Update()
{
base.Update();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,416 @@
using System;
using Beefy.theme.dark;
using Beefy.gfx;
using System.Collections.Generic;
using System.Diagnostics;
namespace IDE.ui
{
class SettingsDialog : PropertiesDialog
{
enum CategoryType
{
Editor,
Keys,
Compiler,
Debugger,
VisualStudio,
COUNT
}
PropPage[] mPropPages = new PropPage[(int32)CategoryType.COUNT] ~
{
for (let propPage in _)
delete propPage;
delete _;
};
[Reflect]
class KeyEntry
{
public String mCommand = new String() ~ delete _;
public List<KeyState> mKeys = new List<KeyState>() ~ DeleteContainerAndItems!(_);
public IDECommand.ContextFlags mContextFlags;
public bool mHasConflict;
}
List<KeyEntry> mKeyEntries ~ DeleteContainerAndItems!(_);
protected override float TopY
{
get
{
return GS!(6);
}
}
public this()
{
mTitle = new String("Settings Properties");
var root = (DarkListViewItem)mCategorySelector.GetRoot();
var item = AddCategoryItem(root, "Editor");
item.Focused = true;
AddCategoryItem(root, "Keys");
AddCategoryItem(root, "Compiler");
AddCategoryItem(root, "Debugger");
AddCategoryItem(root, "Visual Studio");
}
void PopulateEditorOptions()
{
mCurPropertiesTarget = gApp.mSettings.mEditorSettings;
var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot();
var (category, propEntry) = AddPropertiesItem(root, "General");
category.mIsBold = true;
category.mTextColor = cHeaderColor;
AddPropertiesItem(category, "Font", "mFonts");
AddPropertiesItem(category, "Font Size", "mFontSize");
AddPropertiesItem(category, "UI Scale", "mUIScale");
AddPropertiesItem(category, "Autocomplete", "mAutoCompleteShowKind");
AddPropertiesItem(category, "Autocomplete Require Tab", "mAutoCompleteRequireTab");
AddPropertiesItem(category, "Autocomplete Show Documentation", "mAutoCompleteShowDocumentation");
AddPropertiesItem(category, "Show Locator Animation", "mShowLocatorAnim");
AddPropertiesItem(category, "Hilite Symbol at Cursor", "mHiliteCursorReferences");
(?, propEntry) = AddPropertiesItem(category, "Spell Check", "mSpellCheckEnabled");
var resetButton = new DarkButton();
resetButton.Label = "Reset";
resetButton.mOnMouseClick.Add(new (btn) =>
{
SpellChecker.ResetWordList();
if (gApp.mSpellChecker != null)
{
delete gApp.mSpellChecker;
gApp.CreateSpellChecker();
}
});
var valueItem = propEntry.mListViewItem.GetSubItem(1);
valueItem.AddWidget(resetButton);
valueItem.mOnResized.Add(new (evt) =>
{
float btnWidth = DarkTheme.sDarkTheme.mSmallFont.GetWidth(resetButton.Label) + GS!(20);
resetButton.Resize(GetValueEditWidth(valueItem) - btnWidth - GS!(28), GS!(1), btnWidth, GS!(16));
});
AddPropertiesItem(category, "Show Line Numbers", "mShowLineNumbers");
category.Open(true, true);
(category, propEntry) = AddPropertiesItem(root, "Colors");
category.mIsBold = true;
category.mTextColor = cHeaderColor;
AddPropertiesItem(category, "UI Red", "mColors.mUIColorR");
AddPropertiesItem(category, "UI Green", "mColors.mUIColorG");
AddPropertiesItem(category, "UI Blue", "mColors.mUIColorB");
AddPropertiesItem(category, "Text", "mColors.mText");
category.Open(true, true);
}
void PopulateCompilerOptions()
{
mCurPropertiesTarget = gApp.mSettings.mCompilerSettings;
var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot();
var (category, propEntry) = AddPropertiesItem(root, "General");
category.mIsBold = true;
category.mTextColor = cHeaderColor;
AddPropertiesItem(category, "Worker Threads", "mWorkerThreads");
category.Open(true, true);
}
void CommandContextToString(IDECommand.ContextFlags contextFlags, String str)
{
bool isFirst = true;
void AddFlagStr(StringView flagStr)
{
if (isFirst)
{
str.Append(", ");
isFirst = false;
}
str.Append(flagStr);
}
if (contextFlags.HasFlag(.Editor))
AddFlagStr("Editor");
}
void UpdateKeyStates()
{
Debug.Assert((CategoryType)mPropPage.mCategoryType == .Keys);
Dictionary<String, KeyEntry> mappedEntries = scope .();
for (var propEntries in mPropPage.mPropEntries.Values)
{
var propEntry = propEntries[0];
let keyEntry = (KeyEntry)propEntry.mTarget;
keyEntry.mHasConflict = false;
let keys = propEntry.mCurValue.Get<List<KeyState>>();
if (keys.Count == 0)
continue;
let keyEntryStr = new String();
KeyState.ToString(keys, keyEntryStr);
keyEntryStr.Append(" ");
CommandContextToString(keyEntry.mContextFlags, keyEntryStr);
String* keyPtr;
KeyEntry* valuePtr;
if (mappedEntries.TryAdd(keyEntryStr, out keyPtr, out valuePtr))
{
*valuePtr = keyEntry;
}
else
{
let other = *valuePtr;
other.mHasConflict = true;
keyEntry.mHasConflict = true;
delete keyEntryStr;
}
}
for (let keyEntryStr in mappedEntries.Keys)
delete keyEntryStr;
for (var propEntries in mPropPage.mPropEntries.Values)
{
var propEntry = propEntries[0];
let keyEntry = (KeyEntry)propEntry.mTarget;
let listViewItem = (DarkListViewItem)propEntry.mListViewItem.GetSubItem(1);
listViewItem.mTextColor = keyEntry.mHasConflict ? 0xFFFF8080 : 0xFFFFFFFF;
}
}
void PopulateKeyOptions()
{
mCurPropertiesTarget = gApp.mSettings.mKeySettings;
var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot();
var map = scope Dictionary<String, KeyEntry>();
mKeyEntries = new List<KeyEntry>();
for (var kv in gApp.mCommands.mCommandMap)
{
var keyEntry = new KeyEntry();
keyEntry.mCommand.Set(kv.key);
keyEntry.mContextFlags = kv.value.mContextFlags;
mKeyEntries.Add(keyEntry);
map[keyEntry.mCommand] = keyEntry;
}
for (var mappedEntry in gApp.mSettings.mKeySettings.mEntries)
{
KeyEntry keyEntry;
if (!map.TryGetValue(mappedEntry.mCommand, out keyEntry))
continue;
for (let keyState in mappedEntry.mKeys)
keyEntry.mKeys.Add(keyState.Clone());
}
mKeyEntries.Sort(scope (lhs, rhs) => String.Compare(lhs.mCommand, rhs.mCommand, true));
for (var keyEntry in mKeyEntries)
{
mCurPropertiesTarget = keyEntry;
var (category, propEntry) = AddPropertiesItem(root, keyEntry.mCommand, "mKeys");
}
UpdateKeyStates();
}
void PopulateVSOptions()
{
mCurPropertiesTarget = gApp.mSettings.mVSSettings;
var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot();
/*var (category, propEntry) = AddPropertiesItem(root, "General");
category.mIsBold = true;
category.mTextColor = cHeaderColor;*/
var (category, propEntry) = AddPropertiesItem(root, "Tool Path (x86)", "mBin32Path", null, .BrowseForFolder);
propEntry.mRelPath = new String(gApp.mInstallDir);
(category, propEntry) = AddPropertiesItem(root, "Tool Path (x64)", "mBin64Path", null, .BrowseForFolder);
propEntry.mRelPath = new String(gApp.mInstallDir);
(category, propEntry) = AddPropertiesItem(root, "Library Paths (x86)", "mLib32Paths");
propEntry.mRelPath = new String(gApp.mInstallDir);
(category, propEntry) = AddPropertiesItem(root, "Library Paths (x64)", "mLib64Paths");
propEntry.mRelPath = new String(gApp.mInstallDir);
//category.Open(true, true);
}
void PopulateDebuggerOptions()
{
mCurPropertiesTarget = gApp.mSettings.mDebuggerSettings;
var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot();
AddPropertiesItem(root, "Use Symbol Servers", "mUseSymbolServers");
AddPropertiesItem(root, "Symbol Cache Path", "mSymCachePath");
AddPropertiesItem(root, "Symbol File Locations", "mSymbolSearchPath");
AddPropertiesItem(root, "Auto Find Paths", "mAutoFindPaths");
AddPropertiesItem(root, "Profile Sample Rate", "mProfileSampleRate");
}
protected override void ResetSettings()
{
base.ResetSettings();
var targetDict = scope Dictionary<Object, Object>();
switch ((CategoryType)mPropPage.mCategoryType)
{
case .Editor:
Settings.EditorSettings editorSettings = scope .();
editorSettings.SetDefaults();
targetDict[gApp.mSettings.mEditorSettings] = editorSettings;
targetDict[gApp.mSettings.mEditorSettings.mColors] = editorSettings.mColors;
UpdateFromTarget(targetDict);
case .Keys:
Settings.KeySettings keySettings = scope .();
keySettings.SetDefaults();
Dictionary<String, KeyEntry> defaultKeyMap = scope .();
for (var keySettingEntry in keySettings.mEntries)
{
KeyEntry keyEntry = scope:: .();
keyEntry.mCommand.Set(keySettingEntry.mCommand);
for (let keyState in keySettingEntry.mKeys)
keyEntry.mKeys.Add(keyState.Clone());
defaultKeyMap[keyEntry.mCommand] = keyEntry;
}
for (var keyEntry in mKeyEntries)
{
KeyEntry defaultKeyEntry;
defaultKeyMap.TryGetValue(keyEntry.mCommand, out defaultKeyEntry);
if (defaultKeyEntry == null)
{
defaultKeyEntry = scope:: .();
}
targetDict[keyEntry] = defaultKeyEntry;
}
UpdateFromTarget(targetDict);
case .Compiler:
Settings.CompilerSettings compilerSettings = scope .();
compilerSettings.SetDefaults();
targetDict[gApp.mSettings.mCompilerSettings] = compilerSettings;
UpdateFromTarget(targetDict);
case .Debugger:
Settings.DebuggerSettings debuggerSettings = scope .();
debuggerSettings.SetDefaults();
targetDict[gApp.mSettings.mDebuggerSettings] = debuggerSettings;
UpdateFromTarget(targetDict);
case .VisualStudio:
Settings.VSSettings vsSettings = scope .();
vsSettings.SetDefaults();
targetDict[gApp.mSettings.mVSSettings] = vsSettings;
UpdateFromTarget(targetDict);
default:
}
}
protected override void ShowPropPage(int32 categoryTypeInt)
{
base.ShowPropPage(categoryTypeInt);
let categoryType = (CategoryType)categoryTypeInt;
if (mPropPages[(int32)categoryType] == null)
{
CreatePropPage(categoryTypeInt, .AllowSearch | .AllowReset);
mPropPages[categoryTypeInt] = mPropPage;
mPropPage.mPropertiesListView.InitScrollbars(false, true);
//mPropPage.mPropertiesListView.mAutoFocus = true;
mPropPage.mPropertiesListView.mShowColumnGrid = true;
mPropPage.mPropertiesListView.mShowGridLines = true;
switch ((CategoryType)categoryTypeInt)
{
case .Editor:
PopulateEditorOptions();
case .Keys:
PopulateKeyOptions();
case .Compiler:
PopulateCompilerOptions();
case .Debugger:
PopulateDebuggerOptions();
case .VisualStudio:
PopulateVSOptions();
default:
/*mCurPropertiesTarget = gApp.mSettings.mEditorSettings;
PopulateEditorOptions();*/
}
}
mPropPage = mPropPages[(int32)categoryType];
AddPropPageWidget();
ResizeComponents();
}
protected override void UpdatePropertyValue(PropEntry[] propEntries)
{
base.UpdatePropertyValue(propEntries);
var propEntry = propEntries[0];
if (propEntry.mTarget is KeyEntry)
UpdateKeyStates();
}
protected override bool ApplyChanges()
{
bool hadChanges = false;
for (var propPage in mPropPages)
{
if (propPage == null)
continue;
ApplyChanges(propPage, ref hadChanges);
}
if (hadChanges)
{
if (mKeyEntries != null)
{
gApp.mSettings.mKeySettings.Clear();
for (let inEntry in mKeyEntries)
{
if (inEntry.mKeys.IsEmpty)
continue;
let outEntry = new Settings.KeySettings.Entry();
outEntry.mCommand = new String(inEntry.mCommand);
let keyArr = new KeyState[inEntry.mKeys.Count];
for (int i < inEntry.mKeys.Count)
keyArr[i] = inEntry.mKeys[i].Clone();
outEntry.mKeys = keyArr;
gApp.mSettings.mKeySettings.mEntries.Add(outEntry);
}
}
gApp.mSettings.Apply();
}
return true;
}
public override void CalcSize()
{
mWidth = GS!(660);
mHeight = GS!(512);
}
public override void Update()
{
base.Update();
CheckForChanges(mPropPages);
}
}
}

View file

@ -0,0 +1,32 @@
using Beefy.theme.dark;
namespace IDE.ui
{
class SingleLineEditWidgetContent : DarkEditWidgetContent
{
public this()
{
SetFont(DarkTheme.sDarkTheme.mSmallFont, false, false);
mTextInsets.Set(GS!(1), GS!(2), 0, GS!(2));
}
public override float GetLineHeight(int line)
{
return GS!(21);
}
}
class SingleLineEditWidget : DarkEditWidget
{
public this()
: base(new SingleLineEditWidgetContent())
{
mScrollContentInsets.Set(GS!(2), GS!(3), GS!(2), GS!(3));
}
public void ResizeAround(float targetX, float targetY, float width)
{
Resize(targetX - GS!(1), targetY - GS!(1), width + GS!(2), GS!(23));
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

408
IDE/src/ui/StatusBar.bf Normal file
View file

@ -0,0 +1,408 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.gfx;
using Beefy.widgets;
using Beefy.theme.dark;
using Beefy.geom;
using IDE.Debugger;
using IDE;
using System.Diagnostics;
using IDE.Compiler;
namespace IDE.ui
{
public class StatusBar : Widget
{
public int32 mClangCommandQueueSize;
public DarkComboBox mConfigComboBox;
public DarkComboBox mPlatformComboBox;
public bool mWasCompiling;
public int mEvalCount;
public ImageWidget mCancelSymSrvButton;
public int mDirtyDelay;
public int mStatusBoxUpdateCnt = -1;
public this()
{
mConfigComboBox = new DarkComboBox();
mConfigComboBox.mPopulateMenuAction.Add(new => PopulateConfigMenu);
AddWidget(mConfigComboBox);
mPlatformComboBox = new DarkComboBox();
mPlatformComboBox.mPopulateMenuAction.Add(new => PopulatePlatformMenu);
AddWidget(mPlatformComboBox);
}
void PopulateConfigMenu(Menu menu)
{
var nameList = scope List<String>(gApp.mWorkspace.mConfigs.Keys);
nameList.Sort(scope (lhs, rhs) => lhs.CompareTo(rhs, true));
for (var configName in nameList)
{
String dispStr = configName;
/*if (gApp.mConfigName == configName)
{
dispStr = stack String();
dispStr.AppendF("Active({0})", configName);
}*/
var item = menu.AddItem(dispStr);
if (gApp.mConfigName == configName)
item.mBold = true;
item.mOnMenuItemSelected.Add(new (evt) => { SelectConfig(configName); });
}
}
public void SelectConfig(String configName)
{
mConfigComboBox.Label = configName;
gApp.mConfigName.Set(configName);
gApp.CurrentWorkspaceConfigChanged();
MarkDirty();
}
void SelectPlatform(String platformName)
{
mPlatformComboBox.Label = platformName;
gApp.mPlatformName.Set(platformName);
gApp.CurrentWorkspaceConfigChanged();
MarkDirty();
}
void PopulatePlatformMenu(Menu menu)
{
var nameList = scope List<String>();
gApp.mWorkspace.GetPlatformList(nameList);
for (var platformName in nameList)
{
String dispStr = platformName;
/*if (gApp.mPlatformName == platformName)
{
dispStr = stack String();
dispStr.AppendF("Active({0})", platformName);
}*/
var item = menu.AddItem(dispStr);
if (gApp.mPlatformName == platformName)
item.mBold = true;
item.mOnMenuItemSelected.Add(new (evt) => { SelectPlatform(platformName); });
}
}
void ResizeComponents()
{
mConfigComboBox.Resize(mWidth - GS!(440), 0, GS!(120), mHeight + 2);
mPlatformComboBox.Resize(mWidth - GS!(440 + 120), 0, GS!(120), mHeight + 2);
if (mCancelSymSrvButton != null)
mCancelSymSrvButton.Resize(GS!(546), 0, GS!(20), GS!(20));
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
// This marks us dirty on the next frame also
void MarkDirtyEx(int dirtyDelay = 1)
{
mDirtyDelay = Math.Min(dirtyDelay, mDirtyDelay);
MarkDirty();
}
public override void Update()
{
base.Update();
if (mDirtyDelay > 0)
{
if (--mDirtyDelay == 0)
MarkDirty();
}
if (mStatusBoxUpdateCnt != -1)
mStatusBoxUpdateCnt++;
if (gApp.mWorkspace.IsInitialized)
{
mConfigComboBox.Label = gApp.mConfigName;
mPlatformComboBox.Label = gApp.mPlatformName;
}
else
{
mConfigComboBox.Label = "";
mPlatformComboBox.Label = "";
}
bool canChangeConfig = !gApp.IsCompiling && !gApp.mDebugger.mIsRunning && !gApp.AreTestsRunning() && gApp.mWorkspace.IsInitialized;
mConfigComboBox.mDisabled = !canChangeConfig;
mPlatformComboBox.mDisabled = !canChangeConfig;
if ((gApp.IsCompiling || gApp.mRunningTestScript) && (mUpdateCnt % 8 == 0))
MarkDirtyEx(8);
var debugState = gApp.mDebugger.GetRunState();
//if (mWidgetWindow.IsKeyDown(.Control))
//debugState = .SearchingSymSrv;
if (debugState == .DebugEval)
{
mEvalCount++;
MarkDirtyEx();
}
else
mEvalCount = 0;
if (debugState == .SearchingSymSrv)
{
MarkDirtyEx();
if (mCancelSymSrvButton == null)
{
mCancelSymSrvButton = new ImageWidget();
mCancelSymSrvButton.mImage = DarkTheme.sDarkTheme.GetImage(.Close);
mCancelSymSrvButton.mOverImage = DarkTheme.sDarkTheme.GetImage(.CloseOver);
mCancelSymSrvButton.mOnMouseClick.Add(new (evt) => { gApp.mDebugger.CancelSymSrv(); });
AddWidget(mCancelSymSrvButton);
ResizeComponents();
}
float len = GS!(200);
float x = GS!(350);
Rect completionRect = Rect(x, GS!(1), len, GS!(17));
Point mousePos;
if (DarkTooltipManager.CheckMouseover(this, 25, out mousePos, true))
{
if (completionRect.Contains(mousePos.x, mousePos.y))
{
DarkTooltipManager.ShowTooltip(gApp.mSymSrvStatus, this, mousePos.x, mousePos.y);
}
}
}
else
{
if ((DarkTooltipManager.sTooltip != null) && (DarkTooltipManager.sTooltip.mRelWidget == this))
DarkTooltipManager.sTooltip.Close();
if (mCancelSymSrvButton != null)
{
RemoveAndDelete(mCancelSymSrvButton);
mCancelSymSrvButton = null;
}
}
if ((gApp.mBfResolveCompiler != null) && (gApp.mBfResolveCompiler.IsPerformingBackgroundOperation())
#if IDE_C_SUPPORT
|| (gApp.mResolveClang.IsPerformingBackgroundOperation()) ||
(gApp.mDepClang.IsPerformingBackgroundOperation())
#endif
)
{
MarkDirtyEx();
}
}
public override void Draw(Graphics g)
{
bool atError = gApp.mDebugger.GetRunState() == DebugManager.RunState.Exception;
uint32 bkgColor = 0xFF404040;
if (atError)
bkgColor = 0xFF800000;
if (gApp.IsCompiling)
bkgColor = 0xFF303060;
else if (gApp.mDebugger.mIsRunning)
bkgColor = 0xFFCA5100;
else if (gApp.AreTestsRunning())
bkgColor = 0xFF562143;
using (g.PushColor(bkgColor))
g.FillRect(0, 0, mWidth, mHeight);
// Helps debug MarkDirtys
/*using (g.PushColor(Color.FromHSV(Utils.RandFloat(), 1.0f, 1.0f)))
{
g.FillRect(0, mHeight - 4, 4, 4);
}*/
g.SetFont(DarkTheme.sDarkTheme.mSmallFont);
var activeDocument = gApp.GetActiveDocumentPanel();
if (activeDocument is SourceViewPanel)
{
var sourceViewPanel = (SourceViewPanel)activeDocument;
int32 line;
int32 column;
sourceViewPanel.GetCursorPosition(out line, out column);
/*if (true)
{
var ewc = sourceViewPanel.mEditWidget.Content;
int cursorPos = ewc.CursorTextPos;
if (cursorPos < ewc.mData.mTextLength)
{
ewc.mData.mTextIdData.Prepare();
g.DrawString(StackStringFormat!("Id {0}", ewc.mData.mTextIdData.GetIdAtIndex(cursorPos)), mWidth - GS!(320), 0);
}
}*/
g.DrawString(StackStringFormat!("Idx {0}", sourceViewPanel.mEditWidget.Content.CursorTextPos), mWidth - GS!(240), 0);
g.DrawString(StackStringFormat!("Ln {0}", line + 1), mWidth - GS!(160), 0);
g.DrawString(StackStringFormat!("Col {0}", column + 1), mWidth - GS!(80), 0);
}
using (g.PushColor(0xFF101010))
{
//g.FillRect(50 + ((mUpdateCnt) % 50) * 2, 0, 3, mHeight);
}
var bfBuildCompiler = gApp.mBfBuildCompiler;
#if IDE_C_SUPPORT
var buildClang = gApp.mDepClang;
#endif
float? completionPct = null;
if (bfBuildCompiler.HasQueuedCommands())
{
completionPct = bfBuildCompiler.GetCompletionPercentage();
Debug.Assert(completionPct.GetValueOrDefault() >= 0);
}
#if IDE_C_SUPPORT
else if ((gApp.IsCompiling) && (buildClang.mCompileWaitsForQueueEmpty))
{
mClangCommandQueueSize = Math.Max(mClangCommandQueueSize, buildClang.GetCommandQueueSize());
if (mClangCommandQueueSize != 0)
{
int32 itemsLeft = buildClang.GetCommandQueueSize();
completionPct = (mClangCommandQueueSize - itemsLeft) / (float)mClangCommandQueueSize;
Debug.Assert(completionPct.GetValueOrDefault() >= 0);
if (itemsLeft == 0)
mClangCommandQueueSize = 0;
}
}
#endif
//completionPct = 0.4f;
if (completionPct.HasValue)
{
Rect completionRect = Rect(GS!(200), GS!(2), GS!(120), GS!(15));
using (g.PushColor(0xFF000000))
g.FillRect(completionRect.mX, completionRect.mY, completionRect.mWidth, completionRect.mHeight);
completionRect.Inflate(GS!(-1), GS!(-1));
using (g.PushColor(0xFF00FF00))
g.FillRect(completionRect.mX, completionRect.mY, completionRect.mWidth * completionPct.Value, completionRect.mHeight);
}
else if ((gApp.mDebugger.mIsRunning) && (gApp.HaveSourcesChanged()))
{
Rect completionRect = Rect(GS!(200), GS!(1), GS!(120), GS!(17));
using (g.PushColor(0x60000000))
g.FillRect(completionRect.mX, completionRect.mY, completionRect.mWidth, completionRect.mHeight);
completionRect.Inflate(-1, -1);
using (g.PushColor(0x40202080))
g.FillRect(completionRect.mX, completionRect.mY, completionRect.mWidth, completionRect.mHeight);
g.DrawString("Source Changed", GS!(200), GS!(-1.3f), FontAlign.Centered, GS!(120));
}
void DrawStatusBox(StringView str)
{
if (mStatusBoxUpdateCnt == -1)
mStatusBoxUpdateCnt = 0;
float len = GS!(200);
float x = GS!(350);
Rect completionRect = Rect(x, GS!(1), len, GS!(17));
using (g.PushColor(0x60000000))
g.FillRect(completionRect.mX, completionRect.mY, completionRect.mWidth, completionRect.mHeight);
completionRect.Inflate(-1, -1);
//float pulseSpeed = Math.Min(mStatusBoxUpdateCnt * 0.001f, 0.2f);
float pulseSpeed = 0.2f;
float pulsePct = -Math.Cos(Math.Max(mStatusBoxUpdateCnt - 30, 0) * pulseSpeed);
using (g.PushColor(Color.FromHSV(0.1f, 0.5f, (float)Math.Max(pulsePct * 0.15f + 0.3f, 0.3f))))
g.FillRect(completionRect.mX, completionRect.mY, completionRect.mWidth, completionRect.mHeight);
if (mCancelSymSrvButton != null)
mCancelSymSrvButton.mX = completionRect.Right - GS!(16);
g.DrawString(str, x, (int)GS!(-1.3f), FontAlign.Centered, len);
}
if (gApp.mKeyChordState != null)
{
String chordState = scope String();
gApp.mKeyChordState.mCommandMap.ToString(chordState);
chordState.Append(", <Awaiting Key>...");
DrawStatusBox(chordState);
}
else if (mCancelSymSrvButton != null)
{
DrawStatusBox("Retrieving Debug Symbols... ");
}
else if (mEvalCount > 20)
{
DrawStatusBox("Evaluating Expression");
}
else if (gApp.mRunningTestScript)
{
DrawStatusBox("Running Script");
}
else
mStatusBoxUpdateCnt = -1;
g.DrawString(StackStringFormat!("FPS: {0}", gApp.mLastFPS), GS!(4), 0);
String resolveStr = scope String();
let bfResolveCompiler = gApp.mBfResolveCompiler;
if ((bfResolveCompiler != null) && (gApp.mBfResolveCompiler.mThreadWorker.mThreadRunning))
{
resolveStr.Append("B");
}
if ((bfResolveCompiler != null) && (gApp.mBfResolveCompiler.mThreadWorkerHi.mThreadRunning))
{
resolveStr.Append("H");
}
#if IDE_C_SUPPORT
if (gApp.mResolveClang.IsPerformingBackgroundOperation())
{
if (resolveStr.Length > 0)
resolveStr.Append(" & ");
resolveStr.Append("Clang");
}
if (gApp.mDepClang.IsPerformingBackgroundOperation())
{
if (resolveStr.Length > 0)
resolveStr.Append(" ");
resolveStr.Append("ClangB");
}
#endif
/*if (BfPassInstance.sPassInstances.Count > 0)
{
//resolveStr += String.Format(" PassInstances: {0}", BfPassInstance.sPassInstances.Count);
resolveStr += "ResolvePasses: {";
//foreach (var passInstance in BfPassInstance.sPassInstances)
for (int passIdx = 0; passIdx < BfPassInstance.sPassInstances.Count; passIdx++)
{
var passInstance = BfPassInstance.sPassInstances[passIdx];
if (passIdx > 0)
resolveStr += ", ";
if (passInstance.mDbgStr != null)
resolveStr += passInstance.mDbgStr;
resolveStr += String.Format(" #{0}", passInstance.mId);
}
resolveStr += "}";
}*/
if (resolveStr.Length != 0)
g.DrawString(resolveStr, GS!(100), 0);
}
}
}

View file

@ -0,0 +1,772 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Beefy.widgets;
using Beefy.theme;
using Beefy.theme.dark;
using Beefy.gfx;
using Beefy.events;
namespace IDE.ui
{
class NewConfigDialog : IDEDialog
{
TargetedPropertiesDialog mTargetedProperties;
EditWidget mConfigNameEdit;
DarkComboBox mCopiedConfigCombo;
String mCopyConfigName = new String() ~ delete _;
public this(TargetedPropertiesDialog targetedProperties) //: base("New Config", "Config Name")
{
mTargetedProperties = targetedProperties;
mCopyConfigName.Set(mTargetedProperties.mActiveConfigName);
mTitle = new String("New Config");
mConfigNameEdit = AddEdit(mTargetedProperties.mActiveConfigName);
mConfigNameEdit.mEditWidgetContent.SelectAll();
mCopiedConfigCombo = new DarkComboBox();
mCopiedConfigCombo.mPopulateMenuAction.Add(new => PopulateConfigMenu);
AddDialogComponent(mCopiedConfigCombo);
if (!mTargetedProperties.mActiveConfigName.IsEmpty)
mCopiedConfigCombo.Label = (scope String()..AppendF("Active({0})", mTargetedProperties.mActiveConfigName));
AddOkCancelButtons(
new (evt) => { evt.mCloseDialog = Finish(); },
null, 0, 1);
}
void SelectConfig(StringView configName)
{
mCopyConfigName.Set(configName);
}
void PopulateConfigMenu(Menu menu)
{
Menu item;
List<String> sortedConfigNames = scope List<String>(IDEApp.sApp.mWorkspace.mConfigs.Keys);
sortedConfigNames.Sort(scope (a, b) => String.Compare(a, b, true));
if (!mTargetedProperties.mActiveConfigName.IsEmpty)
{
String dispStr = StackStringFormat!("Active({0})", mTargetedProperties.mActiveConfigName);
item = menu.AddItem(dispStr);
item.mOnMenuItemSelected.Add(new (evt) => { SelectConfig(mTargetedProperties.mActiveConfigName); });
}
for (var configName in sortedConfigNames)
{
item = menu.AddItem(configName);
item.mOnMenuItemSelected.Add(new (evt) => { SelectConfig(configName); });
}
}
bool Finish()
{
var text = scope String();
mDialogEditWidget.GetText(text);
return mTargetedProperties.CreateNewConfig(text, mCopyConfigName);
}
public override void CalcSize()
{
mWidth = GS!(300);
mHeight = GS!(140);
}
public override void Draw(Graphics g)
{
base.Draw(g);
DrawLabel(g, mConfigNameEdit, "New Config Name");
DrawLabel(g, mCopiedConfigCombo, "Copy From Config");
}
public override void ResizeComponents()
{
base.ResizeComponents();
float curY = GS!(30);
mConfigNameEdit.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(22));
curY += GS!(42);
mCopiedConfigCombo.Resize(GS!(6), curY, mWidth - GS!(6) - GS!(6), GS!(24));
}
}
class EditTargetDialog : IDEDialog
{
public enum Kind
{
Config,
Platform
}
TargetedPropertiesDialog mTargetedProperties;
IDEListView mListView;
ButtonWidget mDeleteButton;
ButtonWidget mRenameButton;
public class Entry
{
public String mOrigName ~ delete _;
public String mNewName ~ delete _;
public bool mDelete;
}
public List<Entry> mEntries = new .() ~ DeleteContainerAndItems!(_);
Dictionary<ListViewItem, Entry> mEntryMap = new .() ~ delete _;
public this(TargetedPropertiesDialog targetedProperties, Kind kind) //: base("New Config", "Config Name")
{
mTargetedProperties = targetedProperties;
mTitle = new String((kind == .Config) ? "Configuration Manager" : "Platform Manager");
mWindowFlags |= .Resizable;
mListView = new IDEListView();
mListView.mOnEditDone.Add(new => HandleEditDone);
mListView.InitScrollbars(false, true);
mListView.mVertScrollbar.mPageSize = GS!(100);
mListView.mVertScrollbar.mContentSize = GS!(500);
mListView.UpdateScrollbars();
mListView.AddColumn(100, "Name");
mListView.mLabelX = GS!(8);
//mListView.mDragEndHandler += HandleDragEnd;
//mListView.mDragUpdateHandler += HandleDragUpdate;
AddWidget(mListView);
mDeleteButton = AddButton("Delete", new (evt) => { evt.mCloseDialog = false; QueryDelete(); });
mRenameButton = AddButton("Rename", new (evt) => { evt.mCloseDialog = false; QueryRename(); });
}
void HandleEditDone(EditWidget editWidget, bool cancelled)
{
if (cancelled)
return;
let listViewItem = mListView.GetRoot().FindFocusedItem();
if (listViewItem == null)
return;
var entry = mEntryMap[listViewItem];
if (entry.mNewName == null)
entry.mNewName = new String();
else
entry.mNewName.Clear();
editWidget.GetText(entry.mNewName);
entry.mNewName.Trim();
listViewItem.Label = entry.mNewName;
}
void DoDelete()
{
mListView.GetRoot().WithSelectedItems(scope [&](listViewItem) =>
{
let entry = mEntryMap[listViewItem];
entry.mDelete = true;
listViewItem.Remove();
gApp.DeferDelete(listViewItem);
});
}
void QueryDelete()
{
String names = scope String();
int itemCount = 0;
mListView.GetRoot().WithSelectedItems(scope [&](listViewItem) =>
{
if (itemCount > 0)
names.Append(", ");
names.Append(listViewItem.Label);
++itemCount;
});
String queryStr = scope String()..AppendF("Are you sure you want delete '{0}'", names);
let dialog = ThemeFactory.mDefault.CreateDialog("Delete?", queryStr, DarkTheme.sDarkTheme.mIconWarning);
dialog.AddYesNoButtons(new (dlg) => { DoDelete(); }, null, -1, 1);
dialog.PopupWindow(mWidgetWindow);
}
void QueryRename()
{
let listViewItem = mListView.GetRoot().FindFocusedItem();
if (listViewItem == null)
return;
mListView.EditListViewItem(listViewItem);
}
public void Add(StringView name)
{
let entry = new Entry();
entry.mOrigName = new String(name);
mEntries.Add(entry);
}
public void FinishInit()
{
mEntries.Sort(scope (lhs, rhs) => String.Compare(lhs.mOrigName, rhs.mOrigName, true));
for (let entry in mEntries)
{
let listViewItem = mListView.GetRoot().CreateChildItem();
listViewItem.Label = entry.mOrigName;
listViewItem.mOnMouseDown.Add(new => ValueClicked);
mEntryMap[listViewItem] = entry;
}
}
public override void CalcSize()
{
mWidth = GS!(320);
mHeight = GS!(220);
}
public override void ResizeComponents()
{
base.ResizeComponents();
float buttonWidth = GS!(80);
mDeleteButton.Resize(mWidth - buttonWidth - GS!(6), GS!(6), buttonWidth, GS!(24));
mRenameButton.Resize(mWidth - buttonWidth - GS!(6), GS!(34), buttonWidth, GS!(24));
mListView.Resize(GS!(6), GS!(6), mWidth - buttonWidth - GS!(20), mHeight - GS!(48));
}
public override void DrawAll(Graphics g)
{
base.DrawAll(g);
IDEUtils.DrawOutline(g, mListView, 0, 1);
}
public void ValueClicked(MouseEvent theEvent)
{
let clickedItem = (DarkListViewItem)theEvent.mSender;
mListView.SetFocus();
if (theEvent.mBtn == 1)
{
if (!clickedItem.Selected)
mListView.GetRoot().SelectItem(clickedItem, true);
}
else
{
mListView.GetRoot().SelectItem(clickedItem, true);
}
}
}
public class TargetedPropertiesDialog : PropertiesDialog
{
protected const String sConfigLabel = "Configuration:";
protected const String sPlatformLabel = "Platform:";
public String mActiveConfigName = new String() ~ delete _;
public String mActivePlatformName = new String() ~ delete _;
protected List<String> mConfigNames = new .() ~ DeleteContainerAndItems!(_);
protected List<String> mPlatformNames = new .() ~ DeleteContainerAndItems!(_);
protected DarkComboBox mConfigComboBox;
protected DarkComboBox mPlatformComboBox;
protected class ConfigDataGroup
{
public Tuple<String, String> mTarget;
public PropPage[] mPropPages ~ delete _;
public this(int categoryCount)
{
mPropPages = new PropPage[categoryCount];
}
public ~this()
{
for (var propPage in mPropPages)
delete propPage;
}
}
protected Dictionary<Tuple<String, String>, ConfigDataGroup> mTargetedConfigDatas = new Dictionary<Tuple<String, String>, ConfigDataGroup>() ~ delete _;
protected ConfigDataGroup mUntargetedConfigData;
protected List<ConfigDataGroup> mConfigDatas = new List<ConfigDataGroup>() ~ DeleteContainerAndItems!(_);
public this()
{
mActiveConfigName.Set(gApp.mConfigName);
mConfigNames.Add(new String(mActiveConfigName));
mActivePlatformName.Set(gApp.mPlatformName);
mPlatformNames.Add(new String(mActivePlatformName));
mConfigComboBox = new DarkComboBox();
//mConfigComboBox.Label = String.Format("Active({0})", IDEApp.sApp.mConfigName);
mConfigComboBox.mPopulateMenuAction.Add(new => PopulateConfigMenu);
AddWidget(mConfigComboBox);
mPlatformComboBox = new DarkComboBox();
//mPlatformComboBox.Label = String.Format("Active({0})", IDEApp.sApp.mPlatformName);
mPlatformComboBox.mPopulateMenuAction.Add(new => PopulatePlatformMenu);
AddWidget(mPlatformComboBox);
}
public ~this()
{
ClearTargetedData();
}
public void ClearTargetedData()
{
for (var kv in mTargetedConfigDatas)
{
delete kv.key.Item1;
delete kv.key.Item2;
delete kv.value;
mConfigDatas.Remove(kv.value);
}
mTargetedConfigDatas.Clear();
}
public bool IsMultiTargeted()
{
return (mConfigNames.Count != 1) || (mPlatformNames.Count != 1);
}
protected virtual bool IsCategoryTargeted(int32 categoryTypeInt)
{
return false;
}
public virtual void GetConfigList(List<String> configNames)
{
}
public virtual void GetPlatformList(List<String> platformNames)
{
}
protected virtual void CreateNewConfig()
{
DarkDialog dialog = new NewConfigDialog(this);
dialog.PopupWindow(mWidgetWindow);
}
protected void ConfigDeleted(String configName)
{
bool currentChanged = false;
int idx = mConfigNames.IndexOf(configName);
if (idx != -1)
{
delete mConfigNames[idx];
mConfigNames.RemoveAt(idx);
if (mConfigNames.Count == 0)
{
List<String> allConfigs = scope List<String>();
GetConfigList(allConfigs);
allConfigs.Sort(scope (lhs, rhs) => lhs <=> rhs);
mConfigNames.Add(new String(allConfigs[0]));
}
currentChanged = true;
}
if (currentChanged)
SelectConfig(mConfigNames);
}
protected void ConfigRenamed(String from, String to)
{
int idx = mConfigNames.IndexOf(from);
if (idx != -1)
{
mConfigNames[idx].Set(to);
SelectConfig(mConfigNames);
}
MarkDirty();
}
protected void PlatformDeleted(String platformName)
{
bool currentChanged = false;
int idx = mPlatformNames.IndexOf(platformName);
if (idx != -1)
{
delete mPlatformNames[idx];
mPlatformNames.RemoveAt(idx);
if (mPlatformNames.Count == 0)
{
List<String> allPlatforms = scope List<String>();
GetPlatformList(allPlatforms);
allPlatforms.Sort(scope (lhs, rhs) => lhs <=> rhs);
mPlatformNames.Add(new String(allPlatforms[0]));
}
currentChanged = true;
}
if (currentChanged)
SelectPlatform(mPlatformNames);
gApp.mWorkspace.MarkPlatformNamesDirty();
}
protected void PlatformRenamed(String from, String to)
{
int idx = mPlatformNames.IndexOf(from);
if (idx != -1)
{
mPlatformNames[idx].Set(to);
SelectPlatform(mPlatformNames);
}
MarkDirty();
gApp.mWorkspace.MarkPlatformNamesDirty();
}
public virtual void EditConfigs()
{
}
public virtual void EditPlatforms()
{
}
public virtual void PopulateConfigMenu(Menu menu)
{
Menu item;
List<String> sortedConfigNames = scope List<String>();
GetConfigList(sortedConfigNames);
sortedConfigNames.Sort(scope (a, b) => String.Compare(a, b, true));
if (!mActiveConfigName.IsEmpty)
{
String dispStr = StackStringFormat!("Active({0})", mActiveConfigName);
item = menu.AddItem(dispStr);
item.mOnMenuItemSelected.Add(new (evt) => { SelectConfig(mActiveConfigName); });
}
for (var configName in sortedConfigNames)
{
item = menu.AddItem(configName);
item.mOnMenuItemSelected.Add(new (evt) => { SelectConfig(configName); });
}
item = menu.AddItem("<All>");
item.mOnMenuItemSelected.Add(new (evt) => { SelectAllConfigs(); });
item = menu.AddItem("<Multiple...>");
item.mOnMenuItemSelected.Add(new (evt) => { SelectMultipleConfigs(); });
item = menu.AddItem("<New...>");
item.mOnMenuItemSelected.Add(new (evt) => { CreateNewConfig(); });
item = menu.AddItem("<Edit...>");
item.mOnMenuItemSelected.Add(new (evt) => { EditConfigs(); });
}
protected void SelectAllConfigs()
{
ClearAndDeleteItems(mConfigNames);
mConfigComboBox.Label = "<All>";
List<String> configNames = scope List<String>();
GetConfigList(configNames);
for (var configName in configNames)
mConfigNames.Add(new String(configName));
ShowPropPage(mPropPage.mCategoryType);
}
protected void SelectMultipleConfigs()
{
MultiSelectDialog dialog = new MultiSelectDialog();
List<String> configNames = scope List<String>();
GetConfigList(configNames);
for (var configName in configNames)
dialog.Add(configName, mConfigNames.Contains(configName));
dialog.FinishInit();
dialog.AddOkCancelButtons(new (dlg) =>
{
ClearAndDeleteItems(mConfigNames);
for (var entry in dialog.mEntries)
{
if (entry.mCheckbox.Checked)
mConfigNames.Add(new String(entry.mName));
}
if (mConfigNames.IsEmpty)
return;
SelectConfig(mConfigNames);
}, null, 0, 1);
dialog.PopupWindow(mWidgetWindow);
}
public virtual void PopulatePlatformMenu(Menu menu)
{
Menu item;
var sortedPlatformNames = scope List<String>();
GetPlatformList(sortedPlatformNames);
for (var platformName in sortedPlatformNames)
{
if (!platformName.IsEmpty)
{
String dispStr = (IDEApp.sApp.mPlatformName == platformName) ? StackStringFormat!("Active({0})", platformName) : platformName;
item = menu.AddItem(dispStr);
item.mOnMenuItemSelected.Add(new (evt) => { SelectPlatform(platformName); });
}
}
item = menu.AddItem("<All>");
item.mOnMenuItemSelected.Add(new (evt) => { SelectAllPlatforms(); });
item = menu.AddItem("<Multiple...>");
item.mOnMenuItemSelected.Add(new (evt) => { SelectMultiplePlatforms(); });
item = menu.AddItem("<New...>");
item.mOnMenuItemSelected.Add(new (evt) => { CreateNewPlatform(); });
item = menu.AddItem("<Edit...>");
item.mOnMenuItemSelected.Add(new (evt) => { EditPlatforms(); });
}
protected virtual void CreateNewPlatform(String name)
{
}
protected virtual void CreateNewPlatform()
{
DarkDialog dialog = new DarkDialog("New Platform", "Platform Name");
dialog.AddEdit("");
dialog.AddOkCancelButtons(
new (evt) => { var text = scope String(); dialog.mDialogEditWidget.GetText(text); CreateNewPlatform(text); },
null, 0, 1);
dialog.PopupWindow(mWidgetWindow);
}
protected void SelectAllPlatforms()
{
ClearAndDeleteItems(mPlatformNames);
mPlatformComboBox.Label = "<All>";
List<String> platformNames = scope .();
GetPlatformList(platformNames);
for (var platformName in platformNames)
{
mPlatformNames.Add(new String(platformName));
}
ShowPropPage(mPropPage.mCategoryType);
}
protected void SelectMultiplePlatforms()
{
MultiSelectDialog dialog = new MultiSelectDialog();
List<String> platformNames = scope .();
GetPlatformList(platformNames);
for (var platformName in platformNames)
dialog.Add(platformName, mPlatformNames.Contains(platformName));
dialog.FinishInit();
dialog.AddOkCancelButtons(new (dlg) =>
{
ClearAndDeleteItems(mPlatformNames);
for (var entry in dialog.mEntries)
{
if (entry.mCheckbox.Checked)
mPlatformNames.Add(new String(entry.mName));
}
if (mPlatformNames.IsEmpty)
return;
SelectPlatform(mPlatformNames);
}, null, 0, 1);
dialog.PopupWindow(mWidgetWindow);
}
public virtual bool CreateNewConfig(String name, String copiedFromConfig)
{
return false;
}
protected override void ShowPropPage(int32 categoryTypeInt)
{
base.ShowPropPage(categoryTypeInt);
if (IsCategoryTargeted(categoryTypeInt))
{
if (mConfigNames.Count == 1)
{
String dispStr = ((mConfigNames.Count == 1) && (mActiveConfigName == mConfigNames[0])) ? StackStringFormat!("Active({0})", mConfigNames[0]) : mConfigNames[0];
mConfigComboBox.Label = dispStr;
}
mConfigComboBox.mDisabled = false;
if (mPlatformNames.Count == 1)
{
String dispStr = ((mPlatformNames.Count == 1) && (mActivePlatformName == mPlatformNames[0])) ? StackStringFormat!("Active({0})", mPlatformNames[0]) : mPlatformNames[0];
mPlatformComboBox.Label = dispStr;
}
mPlatformComboBox.mDisabled = false;
}
else
{
mConfigComboBox.Label = "N/A";
mConfigComboBox.mDisabled = true;
mPlatformComboBox.Label = "N/A";
mPlatformComboBox.mDisabled = true;
}
}
public void HadExternalChanges(String configName, String platformName)
{
int32 categoryType = mPropPage.mCategoryType;
if (configName != null)
{
if ((mConfigNames.Count > 1) || (mPlatformNames.Count > 1))
{
if ((mConfigNames.Contains(configName)) && (mPlatformNames.Contains(platformName)))
{
if (mPropPage == mUntargetedConfigData.mPropPages[categoryType])
{
RemovePropPage();
}
}
}
if (mTargetedConfigDatas.GetAndRemove(.(configName, platformName)) case .Ok((var key, var configDataGroup)))
{
delete key.Item1;
delete key.Item2;
if (configDataGroup.mPropPages[categoryType] == mPropPage)
RemovePropPage();
mConfigDatas.Remove(configDataGroup);
delete configDataGroup;
}
}
else
{
if (!IsCategoryTargeted(categoryType))
RemovePropPage();
}
if (mPropPage == null)
ShowPropPage(categoryType);
}
protected void SelectConfig(List<String> configNames)
{
if (configNames != mConfigNames)
{
ClearAndDeleteItems(mConfigNames);
for (var configName in configNames)
mConfigNames.Add(configName);
}
if (mConfigNames.Count == 1)
SelectConfig(mConfigNames[0]);
else
{
mConfigComboBox.Label = "<Multiple>";
ShowPropPage(mPropPage.mCategoryType);
}
}
protected void SelectPlatform(List<String> platformNames)
{
if (platformNames != mPlatformNames)
{
ClearAndDeleteItems(mPlatformNames);
for (var platformName in platformNames)
mPlatformNames.Add(platformName);
}
if (mPlatformNames.Count == 1)
SelectPlatform(mPlatformNames[0]);
else
{
mConfigComboBox.Label = "<Multiple>";
ShowPropPage(mPropPage.mCategoryType);
}
}
protected void SelectConfig(String configName)
{
var newConfigName = new String(configName);
ClearAndDeleteItems(mConfigNames);
mConfigNames.Add(newConfigName);
mConfigComboBox.Label = newConfigName;
ShowPropPage(mPropPage.mCategoryType);
}
protected void SelectPlatform(String platformName)
{
var newPlatformName = new String(platformName);
ClearAndDeleteItems(mPlatformNames);
mPlatformNames.Add(newPlatformName);
mPlatformComboBox.Label = newPlatformName;
ShowPropPage(mPropPage.mCategoryType);
}
public override void ResizeComponents()
{
base.ResizeComponents();
float topY = GS!(32);
var font = DarkTheme.sDarkTheme.mSmallFont;
float elementWidth = (mWidth - GS!(6 + 6 + 4)) / 2;
float propTopY = topY;
if ((mSearchEdit != null) && (mResetButton != null))
propTopY += GS!(26);
var fontWidth = font.GetWidth(sConfigLabel) + GS!(6);
mConfigComboBox.ResizeClamped(GS!(6) + fontWidth, GS!(6), elementWidth - fontWidth, GS!(24));
fontWidth = font.GetWidth(sPlatformLabel) + GS!(6);
mPlatformComboBox.ResizeClamped(mConfigComboBox.mX + mConfigComboBox.mWidth + GS!(6) + fontWidth, GS!(6), elementWidth - fontWidth, GS!(24));
mCategorySelector.ResizeClamped(GS!(6), topY, mCategorySelector.mWidth, mHeight - topY - GS!(32));
float catRight = mCategorySelector.mX + mCategorySelector.mWidth;
if (!mCategorySelector.mVisible)
catRight = 0;
mPropPage.mPropertiesListView.ResizeClamped(catRight + GS!(6), propTopY, mWidth - catRight - GS!(12), mHeight - propTopY - GS!(32));
}
public override void Draw(Beefy.gfx.Graphics g)
{
base.Draw(g);
var font = DarkTheme.sDarkTheme.mSmallFont;
g.SetFont(font);
using (g.PushColor(mConfigComboBox.mDisabled ? 0x60FFFFFF : 0xFFFFFFFF))
g.DrawString(sConfigLabel, mConfigComboBox.mX - font.GetWidth(sConfigLabel) - GS!(6), mConfigComboBox.mY + GS!(0));
using (g.PushColor(mPlatformComboBox.mDisabled ? 0x60FFFFFF : 0xFFFFFFFF))
g.DrawString(sPlatformLabel, mPlatformComboBox.mX - font.GetWidth(sPlatformLabel) - GS!(6), mPlatformComboBox.mY + GS!(0));
}
public override void Update()
{
base.Update();
CheckForChanges();
bool hasChanges = false;
for (var targetedConfigData in mConfigDatas)
{
var targetedConfigName = targetedConfigData.mTarget;
bool isCurrent = (targetedConfigName.Item1 == null) ||
((mConfigNames.Contains(targetedConfigName.Item1)) && (mPlatformNames.Contains(targetedConfigName.Item2)));
for (int32 pageIdx = 0; pageIdx < targetedConfigData.mPropPages.Count; pageIdx++)
{
var propPage = targetedConfigData.mPropPages[pageIdx];
if (propPage != null)
{
var categoryItem = mCategoryListViewItems[pageIdx];
if (isCurrent)
categoryItem.mIsBold = propPage.mHasChanges;
hasChanges |= propPage.mHasChanges;
}
}
}
if (hasChanges)
mApplyButton.mDisabled = false;
else
mApplyButton.mDisabled = true;
}
}
}

276
IDE/src/ui/TextPanel.bf Normal file
View file

@ -0,0 +1,276 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using Beefy;
using Beefy.widgets;
using Beefy.geom;
using Beefy.theme.dark;
namespace IDE.ui
{
public abstract class TextPanel : Panel
{
public HoverWatch mHoverWatch;
public bool mDisposed;
public int32 mLastFocusTick;
public abstract SourceEditWidget EditWidget
{
get;
}
public QuickFind mQuickFind;
public ~this()
{
Widget.RemoveAndDelete(mQuickFind);
}
public virtual bool EscapeHandler()
{
if (mHoverWatch != null)
{
mHoverWatch.Close();
return true;
}
if (mQuickFind != null)
{
if (mQuickFind.Close())
return true;
}
var editWidget = EditWidget;
if (editWidget.Content.HasSelection())
{
editWidget.Content.mSelection = null;
return true;
}
return false;
}
public virtual void Dispose()
{
if (mQuickFind != null)
{
//
}
if (mHoverWatch != null)
mHoverWatch.Close();
mDisposed = true;
}
public override void ParentDeleted()
{
if (!mDisposed)
Dispose();
base.ParentDeleted();
}
public virtual void EditGotFocus()
{
}
public virtual void EditLostFocus()
{
}
public bool CheckAllowHoverWatch()
{
if (mHoverWatch != null)
{
if (mHoverWatch.mCloseCountdown == 1)
{
NOP!();
}
bool hasActiveHoverWatch = false;
if (mHoverWatch.mEditWidget != null)
hasActiveHoverWatch = true;
// Allow a sloped area for the cursor to move down-right to the hover widget
// without causing the hover watch to close because we moved the cursor away
// from the hovered text
float xOfs = DarkTooltipManager.sLastRelMousePos.x - mHoverWatch.mOpenMousePos.x;
float yOfs = DarkTooltipManager.sLastRelMousePos.y - mHoverWatch.mOpenMousePos.y;
if ((xOfs >= 0) && (yOfs >= 0) && (yOfs < 24))
{
if (xOfs < yOfs * 4 + 6)
{
hasActiveHoverWatch = true;
}
}
if ((mHoverWatch.mWidgetWindow != null) && (mHoverWatch.mWidgetWindow.mCaptureWidget != null))
{
// Don't close if hover has mouse mousecapture (particularly while dragging scrollbar)
hasActiveHoverWatch = true;
}
if ((mHoverWatch.mWidgetWindow != null) && (mHoverWatch.mWidgetWindow.mOverWidget != null))
{
// Don't close if hover has mouse mousecapture (particularly while dragging scrollbar)
hasActiveHoverWatch = true;
}
/*if (mHoverWatch.mWidgetWindow.mHasMouseInside)
hasActiveHoverWatch = true;*/
if (hasActiveHoverWatch)
{
//if (mHoverWatch.mCloseCountdown > 0)
//Debug.WriteLine("CheckAllowHoverWatch mCloseCountdown = 0");
mHoverWatch.mCloseCountdown = 0;
return false;
}
else
{
//Debug.WriteLine("CheckAllowHoverWatch !hasActiveHoverWatch");
}
}
if (!mWidgetWindow.mHasMouseInside)
return false;
for (WidgetWindow childWindow in mWidgetWindow.mChildWindows)
{
// We're showing an error dialog, don't close mouseover
var dialog = childWindow.mRootWidget as Dialog;
if ((dialog != null) && (dialog.mWindowFlags.HasFlag(BFWindow.Flags.Modal)))
{
return false;
}
}
if (DarkTooltipManager.sTooltip != null)
return false;
var checkWidget = DarkTooltipManager.sLastMouseWidget;
while ((checkWidget != null) && (checkWidget.mWidgetWindow != null))
{
if (checkWidget.mWidgetWindow != mWidgetWindow)
return false; // We have to at least be over this window
if (checkWidget is HoverWatch)
{
var hw = (HoverWatch)checkWidget;
if (hw.HasContentAt(hw.mWidgetWindow.mMouseX, hw.mWidgetWindow.mMouseY))
return false;
}
if (checkWidget is AutoComplete.AutoCompleteListWidget)
return false;
checkWidget = checkWidget.mParent;
}
return true;
}
public override void SetFocus()
{
base.SetFocus();
EditWidget.SetFocus();
}
public virtual void ShowQuickFind(bool isReplace)
{
if (mQuickFind != null)
{
mQuickFind.Close();
delete mQuickFind;
}
mQuickFind = new QuickFind(this, EditWidget, isReplace);
mWidgetWindow.SetFocus(mQuickFind.mFindEditWidget);
Resize(mX, mY, mWidth, mHeight);
}
public virtual void FindNext(int32 dir = 1)
{
if (mQuickFind == null)
{
ShowQuickFind(false);
if (mQuickFind == null)
return;
mQuickFind.Close();
}
mQuickFind.FindNext(dir, false);
}
protected virtual void ResizeComponents()
{
if (mQuickFind != null)
mQuickFind.ResizeSelf();
}
public override void Resize(float x, float y, float width, float height)
{
base.Resize(x, y, width, height);
ResizeComponents();
}
public virtual void RecordHistoryLocation(bool ignoreIfClose = false)
{
}
public override void Update()
{
base.Update();
if (mQuickFind != null)
mQuickFind.UpdateData();
if (mHoverWatch != null)
{
Debug.Assert(mHoverWatch.mTextPanel == this);
}
}
public virtual void Clear()
{
}
}
class EmptyTextPanel : TextPanel
{
public bool mAllowHoverWatch = false;
public Rect? mHoverWatchRect;
public override SourceEditWidget EditWidget
{
get
{
return null;
}
}
public override void Update()
{
base.Update();
if (!CheckAllowHoverWatch())
return;
if (IDEApp.sApp.HasPopupMenus())
return;
if (mHoverWatchRect.HasValue)
{
float x;
float y;
RootToSelfTranslate(mWidgetWindow.mMouseX, mWidgetWindow.mMouseY, out x, out y);
if (mHoverWatchRect.Value.Contains(x, y))
return;
}
if ((mHoverWatch != null) && (mHoverWatch.mCloseDelay == 0))
mHoverWatch.Close();
}
}
}

Some files were not shown because too many files have changed in this diff Show more