using System; using System.Collections; using System.Text; using System.Threading.Tasks; using System.Threading; using System.Diagnostics; using Beefy.utils; using Beefy; using System.IO; using IDE.util; namespace IDE.Compiler { public abstract class CompilerBase : CommandQueueManager { public enum ViewRefreshKind { None, Collapse, FullRefresh } public int32 mResolveAllWait; protected List mQueuedOutput = new List() ~ DeleteContainerAndItems!(_); public ViewRefreshKind 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 _; public SourceHash mSourceHash; } 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() { mResolveAllWait = 2; } public virtual void QueueProjectSource(ProjectSource projectSource, SourceHash sourceHash, bool wantsHash) { ProjectSourceCommand command = new ProjectSourceCommand(); command.mProjectSource = projectSource; command.mSourceString = new String(); var wantsHash; IDEApp.sApp.FindProjectSourceContent(projectSource, out command.mSourceCharIdData, false, command.mSourceString, wantsHash ? &command.mSourceHash : null); if (!(sourceHash case .None)) { if (command.mSourceHash != sourceHash) projectSource.mWasBuiltWithOldHash = true; command.mSourceHash = sourceHash; } 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() { ResolveAllCommand command = new ResolveAllCommand(); QueueCommand(command); } public override void ProcessQueue() { mThreadYieldCount = 0; DoProcessQueue(); } public override void Update() { if (!ThreadRunning) { CheckThreadDone(); if (mWantsActiveViewRefresh != .None) { IDEApp.sApp.RefreshVisibleViews(null, mWantsActiveViewRefresh); mWantsActiveViewRefresh = .None; } 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); } } } }