Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Krüger <mkrueger@xamarin.com>2015-04-17 09:20:49 +0300
committerMike Krüger <mkrueger@xamarin.com>2015-04-17 09:20:49 +0300
commit427b0a002f7e797a368b196de802f69f45e99ad5 (patch)
tree0976e0d88dadb237c4803d66750c89b52224b1bb
parent16f319d4067a2146af0bf10df44efbbe915beb2b (diff)
[Ide] Projections now track editor updates.
Code behind editor gets now updated when a projection changes and orignal projection segments get updated on text changes as well.
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs22
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/Projection.cs67
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/SegmentTree.cs2
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs11
-rw-r--r--main/tests/UnitTests/MonoDevelop.Ide.Editor/TextEditorProjectionTests.cs78
-rw-r--r--main/tests/UnitTests/UnitTests.csproj1
6 files changed, 164 insertions, 17 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs
index f4ee56c67b..4571fefeb8 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/ProjectedDocumentContext.cs
@@ -62,16 +62,22 @@ namespace MonoDevelop.Ide.Editor.Projection
this.projectedEditor = projectedEditor;
this.originalContext = originalContext;
- var originalProjectId = TypeSystemService.GetProjectId (originalContext.Project);
- var originalProject = TypeSystemService.Workspace.CurrentSolution.GetProject (originalProjectId);
-
- projectedDocument = originalProject.AddDocument (
- projectedEditor.FileName,
- projectedEditor
- );
+ if (originalContext.Project != null) {
+ var originalProjectId = TypeSystemService.GetProjectId (originalContext.Project);
+ if (originalProjectId != null) {
+ var originalProject = TypeSystemService.Workspace.CurrentSolution.GetProject (originalProjectId);
+ if (originalProject != null) {
+ projectedDocument = originalProject.AddDocument (
+ projectedEditor.FileName,
+ projectedEditor
+ );
+ }
+ }
+ }
projectedEditor.TextChanged += delegate(object sender, TextChangeEventArgs e) {
- projectedDocument = projectedDocument.WithText (projectedEditor);
+ if (projectedDocument != null)
+ projectedDocument = projectedDocument.WithText (projectedEditor);
ReparseDocument ();
};
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/Projection.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/Projection.cs
index 392de94cd7..432e88edd4 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/Projection.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/Projection/Projection.cs
@@ -37,20 +37,38 @@ namespace MonoDevelop.Ide.Editor.Projection
{
public ITextDocument Document { get; private set; }
- public IReadOnlyList<ProjectedSegment> ProjectedSegments {
- get;
- private set;
+ SegmentTree<ProjectedTreeSegment> originalProjections = new SegmentTree<ProjectedTreeSegment> ();
+ SegmentTree<ProjectedTreeSegment> projectedProjections = new SegmentTree<ProjectedTreeSegment> ();
+
+ class ProjectedTreeSegment : TreeSegment
+ {
+ public ProjectedTreeSegment LinkedTo { get; set; }
+
+ public ProjectedTreeSegment (int offset, int length) : base (offset, length)
+ {
+ }
+ }
+
+ public IEnumerable<ProjectedSegment> ProjectedSegments {
+ get {
+ foreach (var treeSeg in originalProjections) {
+ yield return new ProjectedSegment (treeSeg.Offset, treeSeg.LinkedTo.Offset, treeSeg.Length);
+ }
+ }
}
TextEditor projectedEditor;
- internal TextEditor ProjectedEditor {
- get {
+ internal TextEditor ProjectedEditor
+ {
+ get
+ {
return projectedEditor;
}
}
ProjectedDocumentContext projectedDocumentContext;
+ TextEditor attachedEditor;
internal DocumentContext ProjectedContext {
get {
@@ -59,11 +77,12 @@ namespace MonoDevelop.Ide.Editor.Projection
}
public TextEditor CreateProjectedEditor (DocumentContext originalContext)
- {
+ {
if (projectedEditor == null) {
projectedEditor = TextEditorFactory.CreateNewEditor (Document);
projectedDocumentContext = new ProjectedDocumentContext (projectedEditor, originalContext);
projectedEditor.InitializeExtensionChain (projectedDocumentContext);
+ projectedProjections.InstallListener (projectedEditor);
}
return projectedEditor;
}
@@ -71,9 +90,41 @@ namespace MonoDevelop.Ide.Editor.Projection
public Projection (ITextDocument document, IReadOnlyList<ProjectedSegment> projectedSegments)
{
if (document == null)
- throw new ArgumentNullException ("document");
+ throw new ArgumentNullException (nameof (document));
this.Document = document;
- this.ProjectedSegments = projectedSegments;
+
+ for (int i = 0; i < projectedSegments.Count; i++) {
+ var p = projectedSegments [i];
+ var original = new ProjectedTreeSegment (p.Offset, p.Length);
+ var projected = new ProjectedTreeSegment (p.ProjectedOffset, p.Length);
+ original.LinkedTo = projected;
+ projected.LinkedTo = original;
+ originalProjections.Add (original);
+ projectedProjections.Add (projected);
+ }
+ }
+
+ internal void Dettach ()
+ {
+ attachedEditor.TextChanged += HandleTextChanged;
+ }
+
+ internal void Attach (TextEditor textEditor)
+ {
+ attachedEditor = textEditor;
+ attachedEditor.TextChanged += HandleTextChanged;
+ }
+
+ void HandleTextChanged (object sender, TextChangeEventArgs e)
+ {
+ foreach (var segment in originalProjections) {
+ if (segment.Contains (e.Offset)) {
+ var projectedOffset = e.Offset - segment.Offset + segment.LinkedTo.Offset;
+ projectedEditor.ReplaceText (projectedOffset, e.RemovalLength, e.InsertedText);
+ }
+ }
+
+ originalProjections.UpdateOnTextReplace (sender, e);
}
}
} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/SegmentTree.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/SegmentTree.cs
index 10222c059b..e22632c0b9 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/SegmentTree.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/SegmentTree.cs
@@ -167,7 +167,7 @@ namespace MonoDevelop.Ide.Editor
ownerDocument = null;
}
- void UpdateOnTextReplace (object sender, TextChangeEventArgs e)
+ internal void UpdateOnTextReplace (object sender, TextChangeEventArgs e)
{
if (e.RemovalLength == 0) {
var length = e.InsertionLength;
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs
index 7f5ea69ace..f143276e14 100644
--- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs
@@ -1170,7 +1170,18 @@ namespace MonoDevelop.Ide.Editor
{
if (ctx == null)
throw new ArgumentNullException ("ctx");
+ if (this.projections != null) {
+ foreach (var projection in this.projections) {
+ projection.Dettach ();
+ }
+ }
this.projections = projections;
+ if (projections != null) {
+ foreach (var projection in projections) {
+ projection.Attach (this);
+ }
+ }
+
if ((disabledFeatures & DisabledProjectionFeatures.SemanticHighlighting) != DisabledProjectionFeatures.SemanticHighlighting) {
if (SemanticHighlighting is ProjectedSemanticHighlighting) {
((ProjectedSemanticHighlighting)SemanticHighlighting).UpdateProjection (projections);
diff --git a/main/tests/UnitTests/MonoDevelop.Ide.Editor/TextEditorProjectionTests.cs b/main/tests/UnitTests/MonoDevelop.Ide.Editor/TextEditorProjectionTests.cs
new file mode 100644
index 0000000000..5cc9c56ce9
--- /dev/null
+++ b/main/tests/UnitTests/MonoDevelop.Ide.Editor/TextEditorProjectionTests.cs
@@ -0,0 +1,78 @@
+//
+// TextEditorProjectionTests.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using NUnit.Framework;
+using System.Collections.Generic;
+using MonoDevelop.Ide.Editor.Projection;
+using MonoDevelop.Core.Text;
+using MonoDevelop.Ide.Gui;
+using MonoDevelop.CSharpBinding;
+using UnitTests;
+using MonoDevelop.CSharpBinding.Tests;
+using System.Linq;
+
+namespace MonoDevelop.Ide.Editor
+{
+ [TestFixture]
+ public class TextEditorProjectionTests : TestBase
+ {
+ [Test]
+ public void TestProjectionUpdate ()
+ {
+ var editor = TextEditorFactory.CreateNewEditor ();
+ editor.Text = "1234567890";
+
+ var projectedDocument = TextEditorFactory.CreateNewDocument (
+ new StringTextSource ("__12__34__56__78__90"),
+ "a"
+ );
+
+ var segments = new List<ProjectedSegment> ();
+ for (int i = 0; i < 5; i++) {
+ segments.Add (new ProjectedSegment (i * 2, 2 + i * 4, 2));
+ }
+ var projection = new Projection.Projection (projectedDocument, segments);
+ var tww = new TestWorkbenchWindow ();
+ var content = new TestViewContent ();
+ tww.ViewContent = content;
+
+ var originalContext = new Document (tww);
+ var projectedEditor = projection.CreateProjectedEditor (originalContext);
+ editor.SetOrUpdateProjections (originalContext, new [] { projection }, TypeSystem.DisabledProjectionFeatures.All);
+ editor.InsertText (1, "foo");
+ Assert.AreEqual ("__1foo2__34__56__78__90", projectedEditor.Text);
+
+ Assert.AreEqual (2 , projection.ProjectedSegments.ElementAt (0).ProjectedOffset);
+ Assert.AreEqual (2 + "foo".Length, projection.ProjectedSegments.ElementAt (0).Length);
+ for (int i = 1; i < 5; i++) {
+ Assert.AreEqual (2 + i * 4 + "foo".Length, projection.ProjectedSegments.ElementAt (i).ProjectedOffset);
+ Assert.AreEqual (2, projection.ProjectedSegments.ElementAt (i).Length);
+ }
+
+ }
+ }
+}
+
diff --git a/main/tests/UnitTests/UnitTests.csproj b/main/tests/UnitTests/UnitTests.csproj
index 95c9eeb799..37e796a3fe 100644
--- a/main/tests/UnitTests/UnitTests.csproj
+++ b/main/tests/UnitTests/UnitTests.csproj
@@ -281,6 +281,7 @@
<Compile Include="MonoDevelop.Ide.Editor\Tests\SimpleReadonlyDocument_Tests.cs" />
<Compile Include="MonoDevelop.Ide.Editor\Tests\MonoTextEditorImplementationTests.cs" />
<Compile Include="MonoDevelop.Ide.Editor\Commands\CodeCommentTests.cs" />
+ <Compile Include="MonoDevelop.Ide.Editor\TextEditorProjectionTests.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\md.targets" />