Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RemoveBackwardsCompatibility/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Formatter/FormattingChanges.cs

Last change on this file was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 5.8 KB
Line 
1//
2// CSharpFormatter.cs
3//
4// Author:
5//       Mike KrÃŒger <mkrueger@xamarin.com>
6//
7// Copyright (c) 2013 Xamarin Inc. (http://xamarin.com)
8//
9// Permission is hereby granted, free of charge, to any person obtaining a copy
10// of this software and associated documentation files (the "Software"), to deal
11// in the Software without restriction, including without limitation the rights
12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13// copies of the Software, and to permit persons to whom the Software is
14// furnished to do so, subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be included in
17// all copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25// THE SOFTWARE.
26using System;
27using ICSharpCode.NRefactory.Editor;
28using System.Threading;
29using System.Linq;
30using ICSharpCode.NRefactory.CSharp.Refactoring;
31using ICSharpCode.NRefactory.TypeSystem;
32using System.Collections.Generic;
33
34namespace ICSharpCode.NRefactory.CSharp
35{
36  /// <summary>
37  /// The formatting changes are used to format a specific region inside a document and apply a minimal formatting
38  /// changeset to a given document. This is useful for a text editor environment.
39  /// </summary>
40  public class FormattingChanges
41  {
42    readonly IDocument document;
43    readonly internal List<TextReplaceAction> changes = new List<TextReplaceAction> ();
44
45    internal FormattingChanges (IDocument document)
46    {
47      if (document == null)
48        throw new ArgumentNullException("document");
49      this.document = document;
50    }
51
52    public int Count {
53      get {
54        return changes.Count;
55      }
56    }
57
58    /// <summary>
59    /// Applies the changes to the input document.
60    /// </summary>
61    public void ApplyChanges()
62    {
63      ApplyChanges(0, document.TextLength, document.Replace, (o, l, v) => document.GetText(o, l) == v);
64    }
65
66    public void ApplyChanges(int startOffset, int length)
67    {
68      ApplyChanges(startOffset, length, document.Replace, (o, l, v) => document.GetText(o, l) == v);
69    }
70
71    /// <summary>
72    /// Applies the changes to the given Script instance.
73    /// </summary>
74    public void ApplyChanges(Script script)
75    {
76      ApplyChanges(0, document.TextLength, script.Replace);
77    }
78
79    public void ApplyChanges(int startOffset, int length, Script script)
80    {
81      ApplyChanges(startOffset, length, script.Replace);
82    }
83
84    public void ApplyChanges(int startOffset, int length, Action<int, int, string> documentReplace, Func<int, int, string, bool> filter = null)
85    {
86      int endOffset = startOffset + length;
87      //      Console.WriteLine ("apply:"+ startOffset + "->" + endOffset);
88      //      Console.WriteLine (document.Text.Substring (0, startOffset) + new string ('x',length) + document.Text.Substring (startOffset+ length));
89
90      TextReplaceAction previousChange = null;
91      int delta = 0;
92      var depChanges = new List<TextReplaceAction> ();
93      foreach (var change in changes.OrderBy(c => c.Offset)) {
94        if (previousChange != null) {
95          if (change.Equals(previousChange)) {
96            // ignore duplicate changes
97            continue;
98          }
99          if (change.Offset < previousChange.Offset + previousChange.RemovalLength) {
100            throw new InvalidOperationException ("Detected overlapping changes " + change + "/" + previousChange);
101          }
102        }
103        previousChange = change;
104        bool skipChange = change.Offset + change.RemovalLength < startOffset || change.Offset > endOffset;
105        skipChange |= filter != null && filter(change.Offset + delta, change.RemovalLength, change.NewText);
106        skipChange &= !depChanges.Contains(change);
107        if (!skipChange) {
108          documentReplace(change.Offset + delta, change.RemovalLength, change.NewText);
109          delta += change.NewText.Length - change.RemovalLength;
110          if (change.DependsOn != null) {
111            depChanges.Add(change.DependsOn);
112          }
113        }
114      }
115      changes.Clear();
116    }
117
118    internal TextReplaceAction AddChange(int offset, int removedChars, string insertedText)
119    {
120      if (offset < 0)
121        throw new ArgumentOutOfRangeException("offset", "Should be >= 0");
122      if (offset >= document.TextLength)
123        throw new ArgumentOutOfRangeException("offset", "Should be < document.TextLength");
124      if (removedChars < 0)
125        throw new ArgumentOutOfRangeException("removedChars", "Should be >= 0");
126      if (removedChars > offset + document.TextLength)
127        throw new ArgumentOutOfRangeException("removedChars", "Tried to remove beyond end of text");
128      if (removedChars == 0 && string.IsNullOrEmpty (insertedText))
129        return null;
130      var action = new TextReplaceAction (offset, removedChars, insertedText);
131      changes.Add(action);
132      return action;
133    }
134   
135    internal sealed class TextReplaceAction
136    {
137      internal readonly int Offset;
138      internal readonly int RemovalLength;
139      internal readonly string NewText;
140      internal TextReplaceAction DependsOn;
141
142      public TextReplaceAction (int offset, int removalLength, string newText)
143      {
144        this.Offset = offset;
145        this.RemovalLength = removalLength;
146        this.NewText = newText ?? string.Empty;
147      }
148
149      public override bool Equals(object obj)
150      {
151        TextReplaceAction other = obj as TextReplaceAction;
152        if (other == null) {
153          return false;
154        }
155        return this.Offset == other.Offset && this.RemovalLength == other.RemovalLength && this.NewText == other.NewText;
156      }
157
158      public override int GetHashCode()
159      {
160        return 0;
161      }
162
163      public override string ToString()
164      {
165        return string.Format("[TextReplaceAction: Offset={0}, RemovalLength={1}, NewText={2}]", Offset, RemovalLength, NewText);
166      }
167    }
168  }
169}
Note: See TracBrowser for help on using the repository browser.