~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.CSharp/Formatter/FormattingChanges.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
Import upstream version 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
26
using System;
 
27
using ICSharpCode.NRefactory.Editor;
 
28
using System.Threading;
 
29
using System.Linq;
 
30
using ICSharpCode.NRefactory.CSharp.Refactoring;
 
31
using ICSharpCode.NRefactory.TypeSystem;
 
32
using System.Collections.Generic;
 
33
 
 
34
namespace 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
                /// <summary>
 
53
                /// Applies the changes to the input document.
 
54
                /// </summary>
 
55
                public void ApplyChanges()
 
56
                {
 
57
                        ApplyChanges(0, document.TextLength, document.Replace, (o, l, v) => document.GetText(o, l) == v);
 
58
                }
 
59
 
 
60
                public void ApplyChanges(int startOffset, int length)
 
61
                {
 
62
                        ApplyChanges(startOffset, length, document.Replace, (o, l, v) => document.GetText(o, l) == v);
 
63
                }
 
64
 
 
65
                /// <summary>
 
66
                /// Applies the changes to the given Script instance.
 
67
                /// </summary>
 
68
                public void ApplyChanges(Script script)
 
69
                {
 
70
                        ApplyChanges(0, document.TextLength, script.Replace);
 
71
                }
 
72
 
 
73
                public void ApplyChanges(int startOffset, int length, Script script)
 
74
                {
 
75
                        ApplyChanges(startOffset, length, script.Replace);
 
76
                }
 
77
 
 
78
                public void ApplyChanges(int startOffset, int length, Action<int, int, string> documentReplace, Func<int, int, string, bool> filter = null)
 
79
                {
 
80
                        int endOffset = startOffset + length;
 
81
                        //                      Console.WriteLine ("apply:"+ startOffset + "->" + endOffset);
 
82
                        //                      Console.WriteLine (document.Text.Substring (0, startOffset) + new string ('x',length) + document.Text.Substring (startOffset+ length));
 
83
 
 
84
                        TextReplaceAction previousChange = null;
 
85
                        int delta = 0;
 
86
                        var depChanges = new List<TextReplaceAction> ();
 
87
                        foreach (var change in changes.OrderBy(c => c.Offset)) {
 
88
                                if (previousChange != null) {
 
89
                                        if (change.Equals(previousChange)) {
 
90
                                                // ignore duplicate changes
 
91
                                                continue;
 
92
                                        }
 
93
                                        if (change.Offset < previousChange.Offset + previousChange.RemovalLength) {
 
94
                                                throw new InvalidOperationException ("Detected overlapping changes " + change + "/" + previousChange);
 
95
                                        }
 
96
                                }
 
97
                                previousChange = change;
 
98
                                bool skipChange = change.Offset + change.RemovalLength < startOffset || change.Offset > endOffset;
 
99
                                skipChange |= filter != null && filter(change.Offset + delta, change.RemovalLength, change.NewText);
 
100
                                skipChange &= !depChanges.Contains(change);
 
101
                                if (!skipChange) {
 
102
                                        documentReplace(change.Offset + delta, change.RemovalLength, change.NewText);
 
103
                                        delta += change.NewText.Length - change.RemovalLength;
 
104
                                        if (change.DependsOn != null) {
 
105
                                                depChanges.Add(change.DependsOn);
 
106
                                        }
 
107
                                }
 
108
                        }
 
109
                        changes.Clear();
 
110
                }
 
111
 
 
112
                internal TextReplaceAction AddChange(int offset, int removedChars, string insertedText)
 
113
                {
 
114
                        if (removedChars == 0 && string.IsNullOrEmpty (insertedText))
 
115
                                return null;
 
116
                        var action = new TextReplaceAction (offset, removedChars, insertedText);
 
117
                        changes.Add(action);
 
118
                        return action;
 
119
                }
 
120
                
 
121
                internal sealed class TextReplaceAction
 
122
                {
 
123
                        internal readonly int Offset;
 
124
                        internal readonly int RemovalLength;
 
125
                        internal readonly string NewText;
 
126
                        internal TextReplaceAction DependsOn;
 
127
 
 
128
                        public TextReplaceAction (int offset, int removalLength, string newText)
 
129
                        {
 
130
                                this.Offset = offset;
 
131
                                this.RemovalLength = removalLength;
 
132
                                this.NewText = newText ?? string.Empty;
 
133
                        }
 
134
 
 
135
                        public override bool Equals(object obj)
 
136
                        {
 
137
                                TextReplaceAction other = obj as TextReplaceAction;
 
138
                                if (other == null) {
 
139
                                        return false;
 
140
                                }
 
141
                                return this.Offset == other.Offset && this.RemovalLength == other.RemovalLength && this.NewText == other.NewText;
 
142
                        }
 
143
 
 
144
                        public override int GetHashCode()
 
145
                        {
 
146
                                return 0;
 
147
                        }
 
148
 
 
149
                        public override string ToString()
 
150
                        {
 
151
                                return string.Format("[TextReplaceAction: Offset={0}, RemovalLength={1}, NewText={2}]", Offset, RemovalLength, NewText);
 
152
                        }
 
153
                }
 
154
        }
 
155
}