mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 04:22:20 +02:00
Relaxed project name restrictions. Auto-refresh of installed libraries.
This commit is contained in:
parent
b3354ee635
commit
4d55a32c90
6 changed files with 143 additions and 27 deletions
|
@ -3,6 +3,8 @@ using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Beefy.utils;
|
using Beefy.utils;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace IDE
|
namespace IDE
|
||||||
{
|
{
|
||||||
|
@ -14,6 +16,68 @@ namespace IDE
|
||||||
public SemVer mVersion ~ delete _;
|
public SemVer mVersion ~ delete _;
|
||||||
public VerSpecRecord mLocation ~ delete _;
|
public VerSpecRecord mLocation ~ delete _;
|
||||||
public ConfigFile mConfigFile;
|
public ConfigFile mConfigFile;
|
||||||
|
|
||||||
|
public bool mParsedConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Registry
|
||||||
|
{
|
||||||
|
public List<RegistryEntry> mEntries = new List<RegistryEntry>() ~ DeleteContainerAndItems!(_);
|
||||||
|
public Monitor mMonitor = new .() ~ delete _;
|
||||||
|
public WaitEvent mEvent = new .() ~ delete _;
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
mEvent.WaitFor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ParseConfig(RegistryEntry entry)
|
||||||
|
{
|
||||||
|
entry.mParsedConfig = true;
|
||||||
|
|
||||||
|
if (entry.mLocation.mVerSpec case .Path(let path))
|
||||||
|
{
|
||||||
|
String configPath = scope String()..AppendF("{}/BeefProj.toml", path);
|
||||||
|
StructuredData sd = scope .();
|
||||||
|
if (sd.Load(configPath) case .Ok)
|
||||||
|
{
|
||||||
|
using (sd.Open("Project"))
|
||||||
|
{
|
||||||
|
var projName = scope String();
|
||||||
|
sd.GetString("Name", projName);
|
||||||
|
if (!projName.IsEmpty)
|
||||||
|
{
|
||||||
|
using (mMonitor.Enter())
|
||||||
|
entry.mProjName.Set(projName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WaitFor()
|
||||||
|
{
|
||||||
|
mEvent.WaitFor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resolve()
|
||||||
|
{
|
||||||
|
// NOTE: We allow a race condition where ParseConfig can possibly occur on multiple threads
|
||||||
|
// at the same time
|
||||||
|
for (var entry in mEntries)
|
||||||
|
{
|
||||||
|
if (!entry.mParsedConfig)
|
||||||
|
ParseConfig(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
mEvent.Set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartResolve()
|
||||||
|
{
|
||||||
|
var thread = new Thread(new => Resolve);
|
||||||
|
thread.Start(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LibDirectory
|
public class LibDirectory
|
||||||
|
@ -29,9 +93,16 @@ namespace IDE
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ConfigFile> mConfigFiles = new List<ConfigFile>() ~ DeleteContainerAndItems!(_);
|
List<ConfigFile> mConfigFiles = new List<ConfigFile>() ~ DeleteContainerAndItems!(_);
|
||||||
public List<RegistryEntry> mRegistry = new List<RegistryEntry>() ~ DeleteContainerAndItems!(_);
|
public Registry mRegistry ~ delete _;
|
||||||
List<String> mConfigPathQueue = new List<String>() ~ DeleteContainerAndItems!(_);
|
List<String> mConfigPathQueue = new List<String>() ~ DeleteContainerAndItems!(_);
|
||||||
List<LibDirectory> mLibDirectories = new List<LibDirectory>() ~ DeleteContainerAndItems!(_);
|
List<LibDirectory> mLibDirectories = new List<LibDirectory>() ~ DeleteContainerAndItems!(_);
|
||||||
|
List<FileSystemWatcher> mWatchers = new .() ~ DeleteContainerAndItems!(_);
|
||||||
|
public bool mLibsChanged;
|
||||||
|
|
||||||
|
void LibsChanged()
|
||||||
|
{
|
||||||
|
mLibsChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> Load(StringView path)
|
Result<void> Load(StringView path)
|
||||||
{
|
{
|
||||||
|
@ -49,7 +120,7 @@ namespace IDE
|
||||||
{
|
{
|
||||||
RegistryEntry regEntry = new RegistryEntry();
|
RegistryEntry regEntry = new RegistryEntry();
|
||||||
regEntry.mProjName = new String(projName);
|
regEntry.mProjName = new String(projName);
|
||||||
mRegistry.Add(regEntry);
|
mRegistry.mEntries.Add(regEntry);
|
||||||
|
|
||||||
regEntry.mConfigFile = configFile;
|
regEntry.mConfigFile = configFile;
|
||||||
|
|
||||||
|
@ -80,18 +151,15 @@ namespace IDE
|
||||||
{
|
{
|
||||||
RegistryEntry regEntry = new RegistryEntry();
|
RegistryEntry regEntry = new RegistryEntry();
|
||||||
regEntry.mProjName = new String(projName);
|
regEntry.mProjName = new String(projName);
|
||||||
mRegistry.Add(regEntry);
|
mRegistry.mEntries.Add(regEntry);
|
||||||
|
|
||||||
regEntry.mConfigFile = configFile;
|
regEntry.mConfigFile = configFile;
|
||||||
|
|
||||||
var verString = scope String();
|
|
||||||
data.GetString("Version", verString);
|
|
||||||
regEntry.mVersion = new SemVer();
|
regEntry.mVersion = new SemVer();
|
||||||
regEntry.mVersion.Parse("0.0.0");
|
regEntry.mVersion.Parse("0.0.0");
|
||||||
|
|
||||||
regEntry.mLocation = new VerSpecRecord();
|
regEntry.mLocation = new VerSpecRecord();
|
||||||
using (data.Open("Location"))
|
regEntry.mLocation.SetPath(filePath);
|
||||||
regEntry.mLocation.SetPath(filePath);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -116,6 +184,16 @@ namespace IDE
|
||||||
Path.GetAbsolutePath(libDir.mPath, configFile.mConfigDir, absPath);
|
Path.GetAbsolutePath(libDir.mPath, configFile.mConfigDir, absPath);
|
||||||
|
|
||||||
AddFromLibraryPath(absPath);
|
AddFromLibraryPath(absPath);
|
||||||
|
absPath.Append(Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
|
FileSystemWatcher watcher = new FileSystemWatcher(absPath);
|
||||||
|
watcher.OnChanged.Add(new (fileName) => LibsChanged());
|
||||||
|
watcher.OnCreated.Add(new (fileName) => LibsChanged());
|
||||||
|
watcher.OnDeleted.Add(new (fileName) => LibsChanged());
|
||||||
|
watcher.OnRenamed.Add(new (newName, oldName) => LibsChanged());
|
||||||
|
watcher.OnError.Add(new () => LibsChanged());
|
||||||
|
watcher.StartRaisingEvents();
|
||||||
|
mWatchers.Add(watcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,14 +241,18 @@ namespace IDE
|
||||||
|
|
||||||
public Result<void> Load()
|
public Result<void> Load()
|
||||||
{
|
{
|
||||||
ClearAndDeleteItems(mRegistry);
|
mLibsChanged = false;
|
||||||
|
delete mRegistry;
|
||||||
|
mRegistry = new Registry();
|
||||||
ClearAndDeleteItems(mConfigFiles);
|
ClearAndDeleteItems(mConfigFiles);
|
||||||
|
ClearAndDeleteItems(mWatchers);
|
||||||
|
|
||||||
for (int i = mConfigPathQueue.Count - 1; i >= 0; i--)
|
for (int i = mConfigPathQueue.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
let path = mConfigPathQueue[i];
|
let path = mConfigPathQueue[i];
|
||||||
Try!(Load(path));
|
Try!(Load(path));
|
||||||
}
|
}
|
||||||
|
mRegistry.StartResolve();
|
||||||
return .Ok;
|
return .Ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2616,18 +2616,30 @@ namespace IDE
|
||||||
|
|
||||||
if (let project = mWorkspace.FindProject(projectName))
|
if (let project = mWorkspace.FindProject(projectName))
|
||||||
return project;
|
return project;
|
||||||
|
|
||||||
if (useVerSpecRecord.mVerSpec case .SemVer)
|
if (useVerSpecRecord.mVerSpec case .SemVer)
|
||||||
{
|
{
|
||||||
for (int regEntryIdx = mBeefConfig.mRegistry.Count - 1; regEntryIdx >= 0; regEntryIdx--)
|
// First pass we just try to use the 'expected' project name
|
||||||
|
FindLoop: for (int pass < 2)
|
||||||
{
|
{
|
||||||
var regEntry = mBeefConfig.mRegistry[regEntryIdx];
|
using (mBeefConfig.mRegistry.mMonitor.Enter())
|
||||||
|
|
||||||
if (regEntry.mProjName == projectName)
|
|
||||||
{
|
{
|
||||||
useVerSpecRecord = regEntry.mLocation;
|
for (int regEntryIdx = mBeefConfig.mRegistry.mEntries.Count - 1; regEntryIdx >= 0; regEntryIdx--)
|
||||||
verConfigDir = regEntry.mConfigFile.mConfigDir;
|
{
|
||||||
|
var regEntry = mBeefConfig.mRegistry.mEntries[regEntryIdx];
|
||||||
|
|
||||||
|
if ((regEntry.mProjName == projectName) && (!regEntry.mParsedConfig))
|
||||||
|
mBeefConfig.mRegistry.ParseConfig(regEntry);
|
||||||
|
|
||||||
|
if (regEntry.mProjName == projectName)
|
||||||
|
{
|
||||||
|
useVerSpecRecord = regEntry.mLocation;
|
||||||
|
verConfigDir = regEntry.mConfigFile.mConfigDir;
|
||||||
|
break FindLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
mBeefConfig.mRegistry.WaitFor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11072,6 +11084,12 @@ namespace IDE
|
||||||
tabButton.Activate();
|
tabButton.Activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CheckLoadConfig()
|
||||||
|
{
|
||||||
|
if (mBeefConfig.mLibsChanged)
|
||||||
|
LoadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
void LoadConfig()
|
void LoadConfig()
|
||||||
{
|
{
|
||||||
delete mBeefConfig;
|
delete mBeefConfig;
|
||||||
|
|
|
@ -1318,6 +1318,19 @@ namespace IDE
|
||||||
options.mBuildOptions.mOtherLinkFlags.Set("$(LinkFlags)");
|
options.mBuildOptions.mOtherLinkFlags.Set("$(LinkFlags)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void GetSanitizedName(String projectName, String outName, bool allowDot = false)
|
||||||
|
{
|
||||||
|
for (let c in projectName.RawChars)
|
||||||
|
{
|
||||||
|
if ((c.IsLetterOrDigit) || (c == '_'))
|
||||||
|
outName.Append(c);
|
||||||
|
else if (c == '-')
|
||||||
|
outName.Append('_');
|
||||||
|
else if ((c == '.') && (allowDot))
|
||||||
|
outName.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
mRootFolder = new ProjectFolder();
|
mRootFolder = new ProjectFolder();
|
||||||
|
@ -1492,7 +1505,9 @@ namespace IDE
|
||||||
data.Add("Name", mProjectName);
|
data.Add("Name", mProjectName);
|
||||||
data.ConditionalAdd("TargetType", mGeneralOptions.mTargetType, GetDefaultTargetType());
|
data.ConditionalAdd("TargetType", mGeneralOptions.mTargetType, GetDefaultTargetType());
|
||||||
data.ConditionalAdd("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : "");
|
data.ConditionalAdd("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : "");
|
||||||
data.ConditionalAdd("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, mProjectName);
|
var defaultNamespace = scope String();
|
||||||
|
GetSanitizedName(mProjectName, defaultNamespace, true);
|
||||||
|
data.ConditionalAdd("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, defaultNamespace);
|
||||||
WriteStrings("Aliases", mGeneralOptions.mAliases);
|
WriteStrings("Aliases", mGeneralOptions.mAliases);
|
||||||
WriteStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros);
|
WriteStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros);
|
||||||
WriteDistinctOptions(mBeefGlobalOptions.mDistinctBuildOptions);
|
WriteDistinctOptions(mBeefGlobalOptions.mDistinctBuildOptions);
|
||||||
|
@ -1807,7 +1822,9 @@ namespace IDE
|
||||||
data.GetString("Name", mProjectName);
|
data.GetString("Name", mProjectName);
|
||||||
ReadStrings("Aliases", mGeneralOptions.mAliases);
|
ReadStrings("Aliases", mGeneralOptions.mAliases);
|
||||||
data.GetString("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : "");
|
data.GetString("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : "");
|
||||||
data.GetString("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, mProjectName);
|
var defaultNamespace = scope String();
|
||||||
|
GetSanitizedName(mProjectName, defaultNamespace, true);
|
||||||
|
data.GetString("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, defaultNamespace);
|
||||||
ReadStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros);
|
ReadStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros);
|
||||||
for (data.Enumerate("DistinctOptions"))
|
for (data.Enumerate("DistinctOptions"))
|
||||||
{
|
{
|
||||||
|
@ -2317,7 +2334,8 @@ namespace IDE
|
||||||
|
|
||||||
public void SetupDefault(BeefGlobalOptions generalOptions)
|
public void SetupDefault(BeefGlobalOptions generalOptions)
|
||||||
{
|
{
|
||||||
generalOptions.mDefaultNamespace.Set(mProjectName);
|
generalOptions.mDefaultNamespace.Clear();
|
||||||
|
GetSanitizedName(mProjectName, generalOptions.mDefaultNamespace, true);
|
||||||
generalOptions.mStartupObject.Set(scope String()..AppendF("{}.Program", generalOptions.mDefaultNamespace));
|
generalOptions.mStartupObject.Set(scope String()..AppendF("{}.Program", generalOptions.mDefaultNamespace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,9 @@ namespace IDE.ui
|
||||||
|
|
||||||
void FindProjects()
|
void FindProjects()
|
||||||
{
|
{
|
||||||
for (let registryEntry in gApp.mBeefConfig.mRegistry)
|
gApp.CheckLoadConfig();
|
||||||
|
gApp.mBeefConfig.mRegistry.WaitFor();
|
||||||
|
for (let registryEntry in gApp.mBeefConfig.mRegistry.mEntries)
|
||||||
{
|
{
|
||||||
InstalledProject installedProject = new .();
|
InstalledProject installedProject = new .();
|
||||||
installedProject.mName = new String(registryEntry.mProjName);
|
installedProject.mName = new String(registryEntry.mProjName);
|
||||||
|
|
|
@ -71,17 +71,11 @@ namespace IDE.ui
|
||||||
Path.GetAbsolutePath(origDirectory, gApp.mWorkspace.mDir, projDirectory);
|
Path.GetAbsolutePath(origDirectory, gApp.mWorkspace.mDir, projDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNameValid = projName.Length > 0;
|
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)
|
if (!isNameValid)
|
||||||
{
|
{
|
||||||
mNameEdit.SetFocus();
|
mNameEdit.SetFocus();
|
||||||
app.Fail("Invalid project name. The project name can only consist of alphanumeric characters, spaces, dashes, and underscores.");
|
app.Fail("Invalid project name");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1863,6 +1863,8 @@ namespace IDE.ui
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gApp.CheckLoadConfig();
|
||||||
|
|
||||||
//TODO: Protect against importing an existing project
|
//TODO: Protect against importing an existing project
|
||||||
Project proj = new Project();
|
Project proj = new Project();
|
||||||
String projFilePath = scope String(filePath);
|
String projFilePath = scope String(filePath);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue