using System.Text;
using BansheeEngine;
namespace BansheeEditor
{
///
/// Handles various operations related to script code in the active project, like compilation and code editor syncing.
///
public sealed class ScriptCodeManager
{
private bool isGameAssemblyDirty;
private bool isEditorAssemblyDirty;
private CompilerInstance compilerInstance;
///
/// Constructs a new script code manager.
///
internal ScriptCodeManager()
{
ProjectLibrary.OnEntryAdded += OnEntryAdded;
ProjectLibrary.OnEntryRemoved += OnEntryRemoved;
ProjectLibrary.OnEntryImported += OnEntryImported;
}
///
/// Triggers required compilation or code editor syncing if needed.
///
internal void Update()
{
if (CodeEditor.IsSolutionDirty)
CodeEditor.SyncSolution();
if (compilerInstance == null)
{
string outputDir = EditorApplication.ScriptAssemblyPath;
if (isGameAssemblyDirty)
{
compilerInstance = ScriptCompiler.CompileAsync(
ScriptAssemblyType.Game, BuildManager.ActivePlatform, true, outputDir);
EditorApplication.SetStatusCompiling(true);
isGameAssemblyDirty = false;
}
else if (isEditorAssemblyDirty)
{
compilerInstance = ScriptCompiler.CompileAsync(
ScriptAssemblyType.Editor, BuildManager.ActivePlatform, true, outputDir);
EditorApplication.SetStatusCompiling(true);
isEditorAssemblyDirty = false;
}
}
else
{
if (compilerInstance.IsDone)
{
if (compilerInstance.HasErrors)
{
foreach (var msg in compilerInstance.WarningMessages)
Debug.LogError(FormMessage(msg));
foreach (var msg in compilerInstance.ErrorMessages)
Debug.LogError(FormMessage(msg));
}
compilerInstance.Dispose();
compilerInstance = null;
EditorApplication.SetStatusCompiling(false);
EditorApplication.ReloadAssemblies();
}
}
}
///
/// Triggered when a new resource is added to the project library.
///
/// Path of the added resource, relative to the project's resource folder.
private void OnEntryAdded(string path)
{
if (IsCodeEditorFile(path))
CodeEditor.MarkSolutionDirty();
}
///
/// Triggered when a resource is removed from the project library.
///
/// Path of the removed resource, relative to the project's resource folder.
private void OnEntryRemoved(string path)
{
if (IsCodeEditorFile(path))
CodeEditor.MarkSolutionDirty();
}
///
/// Triggered when a resource is (re)imported in the project library.
///
/// Path of the imported resource, relative to the project's resource folder.
private void OnEntryImported(string path)
{
LibraryEntry entry = ProjectLibrary.GetEntry(path);
if (entry == null || entry.Type != LibraryEntryType.File)
return;
FileEntry fileEntry = (FileEntry)entry;
if (fileEntry.ResType != ResourceType.ScriptCode)
return;
ScriptCode codeFile = ProjectLibrary.Load(path);
if(codeFile == null)
return;
if(codeFile.EditorScript)
isEditorAssemblyDirty = true;
else
isGameAssemblyDirty = true;
}
///
/// Checks is the resource at the provided path a file relevant to the code editor.
///
/// Path to the resource, absolute or relative to the project's resources folder.
/// True if the file is relevant to the code editor, false otherwise.
private bool IsCodeEditorFile(string path)
{
LibraryEntry entry = ProjectLibrary.GetEntry(path);
if (entry != null && entry.Type == LibraryEntryType.File)
{
FileEntry fileEntry = (FileEntry)entry;
foreach (var codeType in CodeEditor.CodeTypes)
{
if (fileEntry.ResType == codeType)
return true;
}
}
return false;
}
///
/// Converts data reported by the compiler into a readable string.
///
/// Message data as reported by the compiler.
/// Readable message string.
private string FormMessage(CompilerMessage msg)
{
StringBuilder sb = new StringBuilder();
if (msg.type == CompilerMessageType.Error)
sb.AppendLine("Compiler error: " + msg.message);
else
sb.AppendLine("Compiler warning: " + msg.message);
sb.AppendLine("\tin " + msg.file + "[" + msg.line + ":" + msg.column + "]");
return sb.ToString();
}
}
}