Browse Source

Do not save the highlighter being used if the user didn't change it.

Fixed SD2-1540: When "build only modified projects" is used, projects are not rebuilt after a "Clean" operation

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@4081 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
65019e2fa3
  1. 2
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs
  2. 82
      src/Main/Base/Project/Src/Project/BuildEngine.cs
  3. 2
      src/Main/Base/Project/Src/Project/BuildResults.cs
  4. 1
      src/Main/Base/Project/Src/Project/IBuildFeedbackSink.cs
  5. 10
      src/Main/Base/Project/Src/Services/ProjectService/CompileModifiedProjectsOnly.cs
  6. 31
      src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs
  7. 9
      src/Main/Base/Project/Src/TextEditor/Commands/TextAreaContextmenuCommands.cs
  8. 12
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs
  9. 18
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/TextEditorDisplayBinding.cs
  10. 36
      src/Main/Base/Project/Src/Util/ExtensionMethods.cs

2
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControl.cs

@ -179,7 +179,7 @@ namespace ICSharpCode.TextEditor @@ -179,7 +179,7 @@ namespace ICSharpCode.TextEditor
}
}
public void SetHighlighting(string name)
public virtual void SetHighlighting(string name)
{
Document.HighlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategy(name);
}

82
src/Main/Base/Project/Src/Project/BuildEngine.cs

@ -17,31 +17,52 @@ namespace ICSharpCode.SharpDevelop.Project @@ -17,31 +17,52 @@ namespace ICSharpCode.SharpDevelop.Project
/// <summary>
/// Supports building a project with dependencies or the whole solution.
/// Creates a build graph and then builds it using topological sort.
///
/// Supports building multiple projects in parallel.
///
/// This class is not related to MSBuild: it simply "builds" a project by calling IBuildable.StartBuild.
/// </summary>
public sealed class BuildEngine
{
#region Building in the SharpDevelop GUI
static CancellableProgressMonitor guiBuildProgressMonitor;
/// <summary>
/// Starts to run a build inside the SharpDevelop GUI.
/// Only one build can run inside the GUI at one time.
/// </summary>
/// <param name="project">The project/solution to build.</param>
/// <param name="options">The build options.</param>
public static void BuildInGui(IBuildable project, BuildOptions options)
{
if (project == null)
throw new ArgumentNullException("project");
if (options == null)
throw new ArgumentNullException("options");
WorkbenchSingleton.AssertMainThread();
if (guiBuildProgressMonitor != null) {
BuildResults results = new BuildResults();
results.Add(new BuildError(null, Core.ResourceService.GetString("MainWindow.CompilerMessages.MSBuildAlreadyRunning")));
results.Result = BuildResultCode.MSBuildAlreadyRunning;
options.Callback(results);
if (options.Callback != null) {
options.Callback(results);
}
} else {
guiBuildProgressMonitor = new CancellableProgressMonitor(StatusBarService.CreateProgressMonitor());
Gui.WorkbenchSingleton.Workbench.GetPad(typeof(Gui.CompilerMessageView)).BringPadToFront();
GuiBuildStarted.RaiseEvent(null, new BuildEventArgs(project, options));
StartBuild(project, options,
new MessageViewSink(TaskService.BuildMessageViewCategory),
guiBuildProgressMonitor);
}
}
// TODO: in 4.0, replace ProjectService.BuildStarted/BuildFinished with these events
public static event EventHandler<BuildEventArgs> GuiBuildStarted;
public static event EventHandler<BuildEventArgs> GuiBuildFinished;
/// <summary>
/// Gets whether there is a build currently running inside the SharpDevelop GUI.
/// </summary>
public static bool IsGuiBuildRunning {
get {
WorkbenchSingleton.AssertMainThread();
@ -49,6 +70,10 @@ namespace ICSharpCode.SharpDevelop.Project @@ -49,6 +70,10 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
/// <summary>
/// Cancels the build currently running inside the SharpDevelop GUI.
/// This method does nothing if no build is running.
/// </summary>
public static void CancelGuiBuild()
{
WorkbenchSingleton.AssertMainThread();
@ -77,7 +102,16 @@ namespace ICSharpCode.SharpDevelop.Project @@ -77,7 +102,16 @@ namespace ICSharpCode.SharpDevelop.Project
public void Done(bool success)
{
WorkbenchSingleton.SafeThreadAsyncCall(delegate { guiBuildProgressMonitor = null; });
throw new InvalidOperationException("The Done(IBuildable,BuildOptions,BuildResults) method should be called instead.");
}
public void Done(IBuildable buildable, BuildOptions options, BuildResults results)
{
WorkbenchSingleton.SafeThreadAsyncCall(
delegate {
guiBuildProgressMonitor = null;
GuiBuildFinished.RaiseEvent(null, new BuildEventArgs(buildable, options, results));
});
}
}
@ -152,6 +186,15 @@ namespace ICSharpCode.SharpDevelop.Project @@ -152,6 +186,15 @@ namespace ICSharpCode.SharpDevelop.Project
#endregion
#region StartBuild
/// <summary>
/// Starts to run a build.
/// </summary>
/// <param name="project">The project/solution to build</param>
/// <param name="options">The build options that should be used</param>
/// <param name="realtimeBuildFeedbackSink">The build feedback sink that receives the build output.
/// The output is nearly sent "as it comes in": sometimes output must wait because the BuildEngine
/// will ensure that output from two projects building in parallel isn't interleaved.</param>
/// <param name="progressMonitor">The progress monitor that receives build progress.</param>
public static void StartBuild(IBuildable project, BuildOptions options, IBuildFeedbackSink realtimeBuildFeedbackSink, IProgressMonitor progressMonitor)
{
if (project == null)
@ -180,8 +223,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -180,8 +223,7 @@ namespace ICSharpCode.SharpDevelop.Project
else
engine.results.Add(new BuildError(null, "Cyclic dependency"));
engine.results.Result = BuildResultCode.BuildFileError;
realtimeBuildFeedbackSink.Done(false);
options.Callback(engine.results);
engine.ReportDone();
return;
}
@ -288,12 +330,12 @@ namespace ICSharpCode.SharpDevelop.Project @@ -288,12 +330,12 @@ namespace ICSharpCode.SharpDevelop.Project
readonly BuildOptions options;
IProgressMonitor progressMonitor;
BuildNode rootNode;
IBuildable rootProject;
BuildResults results = new BuildResults();
readonly IBuildable rootProject;
readonly BuildResults results = new BuildResults();
DateTime buildStart;
List<BuildNode> projectsCurrentlyBuilding = new List<BuildNode>();
List<BuildNode> projectsReadyForBuildStart = new List<BuildNode>();
readonly List<BuildNode> projectsCurrentlyBuilding = new List<BuildNode>();
readonly List<BuildNode> projectsReadyForBuildStart = new List<BuildNode>();
int workersToStart, runningWorkers;
private BuildEngine(BuildOptions options, IBuildable rootProject)
@ -497,21 +539,35 @@ namespace ICSharpCode.SharpDevelop.Project @@ -497,21 +539,35 @@ namespace ICSharpCode.SharpDevelop.Project
results.Result = BuildResultCode.Error;
ReportMessageInternal("${res:MainWindow.CompilerMessages.BuildFailed}" + buildTime);
//StatusBarService.SetMessage("${res:MainWindow.CompilerMessages.BuildFailed}");
} else {
results.Result = BuildResultCode.Success;
ReportMessageInternal("${res:MainWindow.CompilerMessages.BuildFinished}" + buildTime);
//StatusBarService.SetMessage("${res:MainWindow.CompilerMessages.BuildFinished}");
}
if (progressMonitor != null) {
progressMonitor.Done();
}
ReportDone();
}
/// <summary>
/// Notifies the callback hooks that the build is done.
/// </summary>
void ReportDone()
{
if (combinedBuildFeedbackSink != null) {
combinedBuildFeedbackSink.Done(results.Result == BuildResultCode.Success);
if (combinedBuildFeedbackSink is MessageViewSink) {
// Special case GUI-builds so that they have more information available:
// (non-GUI builds can get the same information from the options.Callback,
// but the GUI cannot use the callback because the build options are set by
// the code triggering the build)
((MessageViewSink)combinedBuildFeedbackSink).Done(rootProject, options, results);
} else {
combinedBuildFeedbackSink.Done(results.Result == BuildResultCode.Success);
}
}
if (options.Callback != null) {
Gui.WorkbenchSingleton.SafeThreadAsyncCall(r => options.Callback(r), results);
Gui.WorkbenchSingleton.SafeThreadAsyncCall(delegate { options.Callback(results); });
}
}
#endregion

2
src/Main/Base/Project/Src/Project/BuildResults.cs

@ -60,7 +60,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -60,7 +60,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// <summary>
/// Adds a project to the list of built projects.
/// This method is thread-sage.
/// This method is thread-safe.
/// </summary>
public void AddBuiltProject(IBuildable buildable)
{

1
src/Main/Base/Project/Src/Project/IBuildFeedbackSink.cs

@ -11,6 +11,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -11,6 +11,7 @@ namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// Interface for reporting build results in real-time.
/// Project-specific build engines use this interface to report results to the main build engine.
/// </summary>
public interface IBuildFeedbackSink
{

10
src/Main/Base/Project/Src/Services/ProjectService/CompileModifiedProjectsOnly.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -45,7 +45,7 @@ namespace ICSharpCode.SharpDevelop.Project
ProjectService.SolutionClosed += MarkAllForRecompilation;
ProjectService.SolutionConfigurationChanged += MarkAllForRecompilation;
ProjectService.SolutionSaved += MarkAllForRecompilation;
ProjectService.EndBuild += ProjectService_EndBuild;
BuildEngine.GuiBuildFinished += BuildEngine_GuiBuildFinished;
FileUtility.FileSaved += OnFileSaved;
}
@ -55,7 +55,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -55,7 +55,7 @@ namespace ICSharpCode.SharpDevelop.Project
// first call to init causes static ctor calls
}
static void ProjectService_EndBuild(object sender, BuildEventArgs e)
static void BuildEngine_GuiBuildFinished(object sender, BuildEventArgs e)
{
// at the end of an successful build, mark all built projects as unmodified
if (e.Results.Result == BuildResultCode.Success) {
@ -69,6 +69,12 @@ namespace ICSharpCode.SharpDevelop.Project @@ -69,6 +69,12 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
}
// at the end of a cleaning build, mark all projects as requiring a rebuild
if (e.Options.ProjectTarget == BuildTarget.Clean || e.Options.TargetForDependencies == BuildTarget.Clean) {
lock (unmodifiedProjects) {
unmodifiedProjects.Clear();
}
}
}
static IProject GetProjectFromBuildable(IBuildable b)

31
src/Main/Base/Project/Src/Services/ProjectService/ProjectService.cs

@ -662,10 +662,41 @@ namespace ICSharpCode.SharpDevelop.Project @@ -662,10 +662,41 @@ namespace ICSharpCode.SharpDevelop.Project
public class BuildEventArgs : EventArgs
{
/// <summary>
/// The project/solution to be built.
/// </summary>
public readonly IBuildable Buildable;
/// <summary>
/// The build options.
/// </summary>
public readonly BuildOptions Options;
/// <summary>
/// Gets the build results.
/// This property is null for build started events.
/// </summary>
public readonly BuildResults Results;
public BuildEventArgs(IBuildable buildable, BuildOptions options)
: this(buildable, options, null)
{
}
public BuildEventArgs(IBuildable buildable, BuildOptions options, BuildResults results)
{
if (buildable == null)
throw new ArgumentNullException("buildable");
if (options == null)
throw new ArgumentNullException("options");
this.Buildable = buildable;
this.Options = options;
this.Results = results;
}
public BuildEventArgs(BuildResults results)
{
// TODO: remove this constructor in 4.0
this.Results = results;
}
}

9
src/Main/Base/Project/Src/TextEditor/Commands/TextAreaContextmenuCommands.cs

@ -58,14 +58,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands @@ -58,14 +58,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands
}
item.Checked = true;
try {
IHighlightingStrategy strat = HighlightingStrategyFactory.CreateHighlightingStrategy(item.Text);
if (strat == null) {
throw new Exception("Strategy can't be null");
}
control.Document.HighlightingStrategy = strat;
if (control is SharpDevelopTextAreaControl) {
((SharpDevelopTextAreaControl)control).InitializeAdvancedHighlighter();
}
control.SetHighlighting(item.Text);
} catch (HighlightingDefinitionInvalidException ex) {
MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

12
src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs

@ -462,6 +462,18 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -462,6 +462,18 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
InitializeAdvancedHighlighter();
}
public bool HighlightingExplicitlySet { get; set; }
/// <summary>
/// Explicitly set the highlighting to use. Will be persisted.
/// </summary>
public override void SetHighlighting(string name)
{
base.SetHighlighting(name);
this.HighlightingExplicitlySet = true;
InitializeAdvancedHighlighter();
}
public void InitializeAdvancedHighlighter()
{
if (advancedHighlighter != null) {

18
src/Main/Base/Project/Src/TextEditor/Gui/Editor/TextEditorDisplayBinding.cs

@ -265,7 +265,9 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -265,7 +265,9 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
Properties properties = new Properties();
properties.Set("CaretOffset", textEditorControl.ActiveTextAreaControl.Caret.Offset);
properties.Set("VisibleLine", textEditorControl.ActiveTextAreaControl.TextArea.TextView.FirstVisibleLine);
properties.Set("HighlightingLanguage", textEditorControl.Document.HighlightingStrategy.Name);
if (textEditorControl.HighlightingExplicitlySet) {
properties.Set("HighlightingLanguage", textEditorControl.Document.HighlightingStrategy.Name);
}
return properties;
}
@ -274,10 +276,16 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -274,10 +276,16 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
textEditorControl.ActiveTextAreaControl.Caret.Position = textEditorControl.Document.OffsetToPosition(Math.Min(textEditorControl.Document.TextLength, Math.Max(0, properties.Get("CaretOffset", textEditorControl.ActiveTextAreaControl.Caret.Offset))));
// textAreaControl.SetDesiredColumn();
if (textEditorControl.Document.HighlightingStrategy.Name != properties.Get("HighlightingLanguage", textEditorControl.Document.HighlightingStrategy.Name)) {
IHighlightingStrategy highlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategy(properties.Get("HighlightingLanguage", textEditorControl.Document.HighlightingStrategy.Name));
if (highlightingStrategy != null) {
textEditorControl.Document.HighlightingStrategy = highlightingStrategy;
string highlightingName = properties.Get("HighlightingLanguage", string.Empty);
if (!string.IsNullOrEmpty(highlightingName)) {
if (highlightingName == textEditorControl.Document.HighlightingStrategy.Name) {
textEditorControl.HighlightingExplicitlySet = true;
} else {
IHighlightingStrategy highlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategy(highlightingName);
if (highlightingStrategy != null) {
textEditorControl.HighlightingExplicitlySet = true;
textEditorControl.Document.HighlightingStrategy = highlightingStrategy;
}
}
}
textEditorControl.ActiveTextAreaControl.TextArea.TextView.FirstVisibleLine = properties.Get("VisibleLine", 0);

36
src/Main/Base/Project/Src/Util/ExtensionMethods.cs

@ -20,6 +20,42 @@ namespace ICSharpCode.SharpDevelop @@ -20,6 +20,42 @@ namespace ICSharpCode.SharpDevelop
/// </summary>
public static class ExtensionMethods
{
/// <summary>
/// Raises the event.
/// Does nothing if eventHandler is null.
/// Because the event handler is passed as parameter, it is only fetched from the event field one time.
/// This makes
/// <code>MyEvent.RaiseEvent(x,y);</code>
/// thread-safe
/// whereas
/// <code>if (MyEvent != null) MyEvent(x,y);</code>
/// would not be safe.
/// </summary>
public static void RaiseEvent(this EventHandler eventHandler, object sender, EventArgs e)
{
if (eventHandler != null) {
eventHandler(sender, e);
}
}
/// <summary>
/// Raises the event.
/// Does nothing if eventHandler is null.
/// Because the event handler is passed as parameter, it is only fetched from the event field one time.
/// This makes
/// <code>MyEvent.RaiseEvent(x,y);</code>
/// thread-safe
/// whereas
/// <code>if (MyEvent != null) MyEvent(x,y);</code>
/// would not be safe.
/// </summary>
public static void RaiseEvent<T>(this EventHandler<T> eventHandler, object sender, T e) where T : EventArgs
{
if (eventHandler != null) {
eventHandler(sender, e);
}
}
/// <summary>
/// Runs an action for all elements in the input.
/// </summary>

Loading…
Cancel
Save