~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to src/addins/CSharpBinding/MonoDevelop.CSharp.Formatting/CSharpFormatter.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
25
// THE SOFTWARE.
26
 
 
27
26
using System;
28
27
using System.Collections.Generic;
29
28
using System.IO;
43
42
using MonoDevelop.Projects.Text;
44
43
using MonoDevelop.Projects.Policies;
45
44
using MonoDevelop.Ide;
 
45
using MonoDevelop.Refactoring;
 
46
using System.Linq;
 
47
using MonoDevelop.Ide.CodeFormatting;
46
48
 
47
49
namespace MonoDevelop.CSharp.Formatting
48
50
{
49
 
        public class CSharpFormatter : AbstractPrettyPrinter
 
51
        public class CSharpFormatter : AbstractAdvancedFormatter
50
52
        {
51
53
                static internal readonly string MimeType = "text/x-csharp";
52
54
 
53
 
                public CSharpFormatter ()
54
 
                {
55
 
                }
56
 
                static int GetTrailingWhitespaces (StringBuilder sb)
57
 
                {
58
 
                        string str = sb.ToString ();
59
 
                        int i = str.Length - 1;
60
 
                        while (i >= 0 && Char.IsWhiteSpace (str[i])) {
61
 
                                i--;
62
 
                        }
63
 
//                      Console.WriteLine (str.Length - 1 - i);
64
 
                        
65
 
                        return str.Length - 1 - i;
66
 
                }
67
 
                static string CreateWrapperClassForMember (IMember member, bool generateOuterClass, TextEditorData data, out int end)
68
 
                {
69
 
                        if (member == null) {
70
 
                                end = -1;
71
 
                                return "";
72
 
                        }
73
 
                        StringBuilder result = new StringBuilder ();
74
 
                        int offset = data.Document.LocationToOffset (member.Location.Line - 1, 0);
75
 
                        int start = offset;
76
 
                        while (offset < data.Document.Length && data.Document.GetCharAt (offset) != '{') {
77
 
                                offset++;
78
 
                        }
79
 
                        if (data.Caret.Offset < offset) {
80
 
                                end = -1;
81
 
                                return "";
82
 
                        }
83
 
                        end = data.Document.GetMatchingBracketOffset (offset);
84
 
                        if (end < 0)
85
 
                                return "";
86
 
                        
87
 
                        if (generateOuterClass)
88
 
                                result.Append ("class " + (member.DeclaringType != null ? member.DeclaringType.Name : "GenericClass") + " {");
89
 
                        for (int i = start; i <= end; i++) {
90
 
                                char ch = data.Document.GetCharAt (i);
91
 
                                switch (ch) {
92
 
                                case '/':
93
 
                                        if (i + 1 <= end && data.Document.GetCharAt (i + 1) == '/') {
94
 
                                                while (i <= end) {
95
 
                                                        ch = data.Document.GetCharAt (i);
96
 
                                                        result.Append (ch);
97
 
                                                        if (i == '\n' || i == '\r')
98
 
                                                                break;
99
 
                                                        i++;
100
 
                                                }
101
 
                                        }
102
 
                                        break;
103
 
                                case '\n':
104
 
                                case '\r':
105
 
                                        result.Length -= GetTrailingWhitespaces (result);
106
 
                                        break;
107
 
                                default:
108
 
                                        result.Append (ch);
109
 
                                        break;
110
 
                                }
111
 
                        }
112
 
                        if (generateOuterClass)
113
 
                                result.Append ("}");
114
 
                        return result.ToString ();
115
 
                }
116
 
 
117
 
                public static int GetColumn (string wrapper, int i, int tabSize)
118
 
                {
119
 
                        int j = i;
120
 
                        int col = 0;
121
 
                        for (; j < wrapper.Length && (wrapper[j] == ' ' || wrapper[j] == '\t'); j++) {
122
 
                                if (wrapper[j] == ' ') {
123
 
                                        col++;
124
 
                                } else {
125
 
                                        col = GetNextTabstop (col, tabSize);
126
 
                                }
127
 
                        }
128
 
                        return col;
129
 
                }
130
 
                
131
 
                public override bool SupportsOnTheFlyFormatting {
132
 
                        get {
133
 
                                return true;
134
 
                        }
135
 
                }
136
 
                
137
 
                public override void CorrectIndenting (object textEditorData, int line)
138
 
                {
139
 
                        TextEditorData data = (TextEditorData)textEditorData;
 
55
                public override bool SupportsOnTheFlyFormatting { get { return true; } }
 
56
 
 
57
                public override bool SupportsCorrectingIndent { get { return true; } }
 
58
 
 
59
                public override void CorrectIndenting (PolicyContainer policyParent, IEnumerable<string> mimeTypeChain, 
 
60
                        TextEditorData data, int line)
 
61
                {
140
62
                        LineSegment lineSegment = data.Document.GetLine (line);
141
63
                        if (lineSegment == null)
142
64
                                return;
143
 
                        IEnumerable<string> types = MonoDevelop.Ide.DesktopService.GetMimeTypeInheritanceChain (CSharpFormatter.MimeType);
144
 
                        var policy = MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<CSharpFormattingPolicy> (types);
145
 
                        DocumentStateTracker<CSharpIndentEngine> tracker = new DocumentStateTracker<CSharpIndentEngine> (new CSharpIndentEngine (policy), data);
 
65
 
 
66
                        var policy = policyParent.Get<CSharpFormattingPolicy> (mimeTypeChain);
 
67
                        var tracker = new DocumentStateTracker<CSharpIndentEngine> (new CSharpIndentEngine (policy), data);
146
68
                        tracker.UpdateEngine (lineSegment.Offset);
147
69
                        for (int i = lineSegment.Offset; i < lineSegment.Offset + lineSegment.EditableLength; i++) {
148
70
                                tracker.Engine.Push (data.Document.GetCharAt (i));
149
71
                        }
150
 
                        
 
72
 
151
73
                        string curIndent = lineSegment.GetIndentation (data.Document);
152
 
                        
 
74
 
153
75
                        int nlwsp = curIndent.Length;
154
 
//                      int cursor = data.Caret.Offset;
155
 
//                      int pos = lineSegment.Offset;
156
 
//                      int offset = cursor > pos + nlwsp ? cursor - (pos + nlwsp) : 0;
157
76
                        if (!tracker.Engine.LineBeganInsideMultiLineComment || (nlwsp < lineSegment.Length && data.Document.GetCharAt (lineSegment.Offset + nlwsp) == '*')) {
158
77
                                // Possibly replace the indent
159
78
                                string newIndent = tracker.Engine.ThisLineIndent;
160
 
//                              int newIndentLength = newIndent.Length;
161
79
                                if (newIndent != curIndent) 
162
80
                                        data.Replace (lineSegment.Offset, nlwsp, newIndent);
163
81
                        }
164
 
                        
165
 
/*                      
166
 
                        string endIndent = tracker.Engine.ThisLineIndent;
167
 
                        string indent = endIndent.Length < beginIndent.Length ? endIndent : beginIndent;
168
 
                        if (indent != curIndent)
169
 
                                data.Replace (lineSegment.Offset, curIndent.Length, indent);
170
 
                                                 */
171
82
                        tracker.Dispose ();
172
83
                }
173
 
                
174
 
                public override void OnTheFlyFormat (object textEditorData, IType type, IMember member, ProjectDom dom, ICompilationUnit unit, DomLocation caretLocation)
175
 
                {
176
 
                        Format ((TextEditorData)textEditorData, type, member, dom, unit, caretLocation);
177
 
                }
178
 
                
179
 
                public static void Format (TextEditorData data, ProjectDom dom, ICompilationUnit unit, DomLocation caretLocation)
180
 
                {
181
 
                        IType type = NRefactoryResolver.GetTypeAtCursor (unit, unit.FileName, caretLocation);
182
 
                        if (type == null)
183
 
                                return;
184
 
                        Format (data, type, NRefactoryResolver.GetMemberAt (type, unit.FileName, caretLocation), dom, unit, caretLocation);
185
 
                }
186
 
                
187
 
                static string GetIndent (string text)
188
 
                {
189
 
                        StringBuilder result = new StringBuilder ();
190
 
                        foreach (char ch in text) {
191
 
                                if (!char.IsWhiteSpace (ch))
192
 
                                        break;
193
 
                                result.Append (ch);
194
 
                        }
195
 
                        return result.ToString ();
196
 
                }
197
 
                
198
 
                static string RemoveIndent (string text, string indent)
199
 
                {
200
 
                        Document doc = new Document ();
201
 
                        doc.Text = text;
202
 
                        StringBuilder result = new StringBuilder ();
203
 
                        foreach (LineSegment line in doc.Lines) {
204
 
                                string curLineIndent = line.GetIndentation (doc);
205
 
                                int offset = Math.Min (curLineIndent.Length, indent.Length);
206
 
                                result.Append (doc.GetTextBetween (line.Offset + offset, line.EndOffset));
207
 
                        }
208
 
                        return result.ToString ();
209
 
                }
210
 
                
211
 
                static string AddIndent (string text, string indent)
212
 
                {
213
 
                        Document doc = new Document ();
214
 
                        doc.Text = text;
215
 
                        StringBuilder result = new StringBuilder ();
216
 
                        foreach (LineSegment line in doc.Lines) {
217
 
                                if (result.Length > 0)
218
 
                                        result.Append (indent);
219
 
                                result.Append (doc.GetTextAt (line));
220
 
                        }
221
 
                        return result.ToString ();
222
 
                }
223
 
                
224
 
                static string GetIndent (TextEditorData data, int lineNumber)
225
 
                {
226
 
                        return data.Document.GetLine (lineNumber).GetIndentation (data.Document);
227
 
                }
228
 
                
229
 
                public static void Format (TextEditorData data, IType type, IMember member, ProjectDom dom, ICompilationUnit unit, DomLocation caretLocation)
230
 
                {
231
 
                        if (type == null)
232
 
                                return;
233
 
                        if (member == null) {
234
 
                                //                              member = type;
235
 
                                return;
236
 
                        }
237
 
                        string wrapper;
238
 
                        int endPos;
239
 
                        wrapper = CreateWrapperClassForMember (member, member != type, data, out endPos);
240
 
                        if (string.IsNullOrEmpty (wrapper) || endPos < 0)
241
 
                                return;
242
 
                //                      Console.WriteLine (wrapper);
243
 
                        
244
 
                        int bracketIndex = wrapper.IndexOf ('{') + 1;
245
 
                        int col = GetColumn (wrapper, bracketIndex, data.Options.TabSize);
246
 
                        
247
 
                        CSharpFormatter formatter = new CSharpFormatter ();
248
 
                        formatter.startIndentLevel = System.Math.Max (0, col / data.Options.TabSize - 1);
249
 
                        
250
 
                        string formattedText = formatter.InternalFormat (dom != null && dom.Project != null ? dom.Project.Policies : null, MimeType, wrapper, 0, wrapper.Length);
251
 
                        
252
 
                        if (formatter.hasErrors)
253
 
                                return;
254
 
                        
255
 
                        int startPos = data.Document.LocationToOffset (member.Location.Line - 1, 0) - 1;
256
 
                        InFormat = true;
257
 
                        if (member != type) {
258
 
                                int len1 = formattedText.IndexOf ('{') + 1;
259
 
                                int last = formattedText.LastIndexOf ('}');
260
 
                                formattedText = formattedText.Substring (len1, last - len1 - 1).TrimStart ('\n', '\r');
261
 
                        } else {
262
 
                                startPos++;
263
 
                        }
264
 
                        
265
 
                        //Console.WriteLine ("formattedText0:" + formattedText.Replace ("\t", "->").Replace (" ", "Ā°"));
266
 
                        if (member != type) {
267
 
                                string indentToRemove = GetIndent (formattedText);
268
 
                //                              Console.WriteLine ("Remove:" + indentToRemove.Replace ("\t", "->").Replace (" ", "Ā°"));
269
 
                                formattedText = RemoveIndent (formattedText, indentToRemove);
270
 
                        } else {
271
 
                                formattedText = formattedText.TrimStart ();
272
 
                        }
273
 
                        //Console.WriteLine ("Indent:" + GetIndent (data, member.Location.Line - 1).Replace ("\t", "->").Replace (" ", "Ā°"));
274
 
                        //Console.WriteLine ("formattedText1:" + formattedText.Replace ("\t", "->").Replace (" ", "Ā°"));
275
 
                        formattedText = AddIndent (formattedText, GetIndent (data, member.Location.Line - 1));
276
 
                        
277
 
                        Document doc = new Document ();
278
 
                        doc.Text = formattedText;
279
 
                        for (int i = doc.LineCount - 1; i >= 0; i--) {
280
 
                                LineSegment lineSegment = doc.GetLine (i);
281
 
                                if (doc.IsEmptyLine (lineSegment))
282
 
                                        ((IBuffer)doc).Remove (lineSegment.Offset, lineSegment.Length);
283
 
                        }
284
 
                        formattedText = doc.Text;
285
 
                        
286
 
                        //Console.WriteLine ("formattedText3:" + formattedText.Replace ("\t", "->").Replace (" ", "Ā°").Replace ("\n", "\\n").Replace ("\r", "\\r"));
287
 
        
288
 
                        int textLength = CanInsertFormattedText (data, startPos, data.Document.LocationToOffset (caretLocation.Line, caretLocation.Column), formattedText);
289
 
                        if (textLength > 0) {
290
 
//                              Console.WriteLine (formattedText.Substring (0, textLength));
291
 
                                InsertFormattedText (data, startPos, formattedText.Substring (0, textLength).TrimEnd ());
292
 
                        } else {
293
 
                                Console.WriteLine ("Can't insert !!!");
294
 
                        }
295
 
                        InFormat = false;
296
 
                }
297
 
 
298
 
                static int CanInsertFormattedText (TextEditorData data, int offset, int endOffset, string formattedText)
299
 
                {
300
 
                        int textOffset = 0;
301
 
                        endOffset = System.Math.Min (data.Document.Length, endOffset);
302
 
                        
303
 
                        while (textOffset < formattedText.Length && offset < endOffset) {
304
 
                                if (offset < 0) {
305
 
                                        offset++;
306
 
                                        textOffset++;
307
 
                                        continue;
308
 
                                }
309
 
                                char ch1 = data.Document.GetCharAt (offset);
310
 
                                char ch2 = formattedText[textOffset];
311
 
                                bool ch1Ws = Char.IsWhiteSpace (ch1);
312
 
                                bool ch2Ws = Char.IsWhiteSpace (ch2);
313
 
                                //Console.WriteLine ("ch1={0}, ch2={1}", ch1, ch2);
314
 
                                if (ch1 == ch2) {
315
 
                                        textOffset++;
316
 
                                        offset++;
317
 
                                        continue;
318
 
                                } else if (ch1 == '\n' || ch1 == '\r') {
319
 
                                        // skip Ws
320
 
                                        int firstWhitespace = -1;
321
 
                                        while (textOffset < formattedText.Length && IsPlainWhitespace (formattedText[textOffset])) {
322
 
                                                if (firstWhitespace < 0)
323
 
                                                        firstWhitespace = textOffset;
324
 
                                                textOffset++;
325
 
                                        }
326
 
                                        
327
 
                                        if (firstWhitespace >= 0 && firstWhitespace != textOffset && (formattedText[textOffset] == '\n' || formattedText[textOffset] == '\r')) {
328
 
                                                int length = textOffset - firstWhitespace;
329
 
                                                offset += length - 1;
330
 
                                                textOffset++;
331
 
                                        }
332
 
 
333
 
                                        offset++;
334
 
                                        while (offset < data.Caret.Offset && IsPlainWhitespace (data.Document.GetCharAt (offset))) {
335
 
                                                offset++;
336
 
                                        }
337
 
                                        continue;
338
 
                                }
339
 
                                
340
 
                                if (ch2Ws && !ch1Ws) {
341
 
                                        textOffset++;
342
 
                                        continue;
343
 
                                }
344
 
                                if ((!ch2Ws || ch2 == '\n') && ch1Ws) {
345
 
                                        offset++;
346
 
                                        continue;
347
 
                                }
348
 
                                
349
 
                                if (ch1Ws && ch2Ws) {
350
 
                                        textOffset++;
351
 
                                        offset++;
352
 
                                        continue;
353
 
                                }
354
 
                                
355
 
                                return -1;
356
 
                        }
357
 
                        return textOffset - 1;
358
 
                }
359
 
 
360
 
                static void InsertFormattedText (TextEditorData data, int offset, string formattedText)
361
 
                {
362
 
                        data.Document.BeginAtomicUndo ();
363
 
                        //                      DocumentLocation caretLocation = data.Caret.Location;
364
 
                        
365
 
                        int selAnchor = data.IsSomethingSelected ? data.Document.LocationToOffset (data.MainSelection.Anchor) : -1;
366
 
                        int selLead = data.IsSomethingSelected ? data.Document.LocationToOffset (data.MainSelection.Lead) : -1;
367
 
                        int textOffset = 0;
368
 
                        int caretOffset = data.Caret.Offset;
369
 
                        
370
 
//                      Console.WriteLine ("formattedText3:" + formattedText.Replace ("\t", "->").Replace (" ", "Ā°").Replace ("\n", "\\n").Replace ("\r", "\\r"));
371
 
                        while (textOffset < formattedText.Length /*&& offset < caretOffset*/) {
372
 
                                if (offset < 0) {
373
 
                                        offset++;
374
 
                                        textOffset++;
375
 
                                        continue;
376
 
                                }
377
 
                                char ch1 = data.Document.GetCharAt (offset);
378
 
                                char ch2 = formattedText[textOffset];
379
 
                                bool isCh1Eol = ch1 == '\n'|| ch1 == '\r';
380
 
                                
381
 
                                if (ch1 == '\r' && offset + 1 < data.Document.Length && data.Document.GetCharAt (offset + 1) == '\n')  {
382
 
                                        offset++;
383
 
                                        ch1 = '\n';
384
 
                                }
385
 
                                
386
 
                                if (ch1 == ch2 || (ch2 == '\n' && isCh1Eol)) {
387
 
                                        textOffset++;
388
 
                                        offset++;
389
 
                                        continue;
390
 
                                } else if (isCh1Eol) {
391
 
                                        
392
 
                                //      int firstWhitespace = 0;
393
 
                                        
394
 
                                         // skip all white spaces in formatted text - we had a line break
395
 
                                        int firstWhitespace = -1;
396
 
                                        while (textOffset < formattedText.Length && IsPlainWhitespace (formattedText[textOffset])) {
397
 
                                                if (firstWhitespace < 0)
398
 
                                                        firstWhitespace = textOffset;
399
 
                                                textOffset++;
400
 
                                        }
401
 
                                        if (firstWhitespace >= 0 && firstWhitespace != textOffset && formattedText[textOffset] == '\n') {
402
 
                                                int length = textOffset - firstWhitespace - 1;
403
 
                                                data.Insert (offset, formattedText.Substring (firstWhitespace, length) + data.EolMarker);
404
 
                                                data.Document.CommitLineUpdate (data.Document.OffsetToLineNumber (offset));
405
 
                                                length += data.EolMarker.Length;
406
 
                                                if (offset < caretOffset)
407
 
                                                        caretOffset += length;
408
 
                                                if (offset < selAnchor)
409
 
                                                        selAnchor += length;
410
 
                                                if (offset < selLead)
411
 
                                                        selLead += length;
412
 
                                                
413
 
                                                offset += length - 1;
414
 
                                                textOffset++;
415
 
                                        }
416
 
                                        
417
 
                                        offset++;
418
 
                                        while (offset < data.Caret.Offset && IsPlainWhitespace (data.Document.GetCharAt (offset))) {
419
 
                                                offset++;
420
 
                                        }
421
 
                                        continue;
422
 
                                }
423
 
                                bool ch1Ws = Char.IsWhiteSpace (ch1);
424
 
                                bool ch2Ws = Char.IsWhiteSpace (ch2);
425
 
 
426
 
                                if (ch2Ws && !ch1Ws) {
427
 
                                        if (ch2 == '\n') {
428
 
                                                data.Insert (offset, data.EolMarker);
429
 
                                                data.Document.CommitLineUpdate (data.Document.OffsetToLineNumber (offset));
430
 
                                                if (offset < caretOffset)
431
 
                                                        caretOffset += data.EolMarker.Length;
432
 
                                                if (offset < selAnchor)
433
 
                                                        selAnchor += data.EolMarker.Length;
434
 
                                                if (offset < selLead)
435
 
                                                        selLead += data.EolMarker.Length;
436
 
                                                textOffset++;
437
 
                                                offset += data.EolMarker.Length;
438
 
                                        } else {
439
 
                                                data.Insert (offset, ch2.ToString ());
440
 
                                                data.Document.CommitLineUpdate (data.Document.OffsetToLineNumber (offset));
441
 
                                                if (offset < caretOffset)
442
 
                                                        caretOffset++;
443
 
                                                if (offset < selAnchor)
444
 
                                                        selAnchor++;
445
 
                                                if (offset < selLead)
446
 
                                                        selLead++;
447
 
                                                textOffset++;
448
 
                                                offset++;
449
 
                                        }
450
 
                                        continue;
451
 
                                }
452
 
 
453
 
                                if ((!ch2Ws || ch2 == '\n') && ch1Ws) {
454
 
                                        if (offset < caretOffset)
455
 
                                                caretOffset--;
456
 
                                        if (offset < selAnchor)
457
 
                                                selAnchor--;
458
 
                                        if (offset < selLead)
459
 
                                                selLead--;
460
 
                                        data.Remove (offset, 1);
461
 
                                        data.Document.CommitLineUpdate (data.Document.OffsetToLineNumber (offset));
462
 
                                        continue;
463
 
                                }
464
 
                                if (ch1Ws && ch2Ws) {
465
 
                                        data.Replace (offset, 1, ch2.ToString ());
466
 
                                        data.Document.CommitLineUpdate (data.Document.OffsetToLineNumber (offset));
467
 
                                        textOffset++;
468
 
                                        offset++;
469
 
                                        continue;
470
 
                                }
471
 
                                Console.WriteLine ("BAIL OUT");
472
 
                                break;
473
 
                        }
474
 
                        data.Caret.Offset = caretOffset;
475
 
                        
476
 
                        if (selAnchor >= 0)
477
 
                                data.MainSelection = new Selection (data.Document.OffsetToLocation (selAnchor), data.Document.OffsetToLocation (selLead));
478
 
                        data.Document.EndAtomicUndo ();
479
 
                }
480
 
 
481
 
                static bool IsPlainWhitespace (char ch)
482
 
                {
483
 
                        return ch == ' ' || ch == '\t';
484
 
                }
485
 
 
486
 
                public static bool InFormat = false;
487
 
 
488
 
                public override bool CanFormat (string mimeType)
489
 
                {
490
 
                        return mimeType == MimeType;
491
 
                }
492
 
 
493
 
                static int GetNextTabstop (int currentColumn, int tabSize)
494
 
                {
495
 
                        int result = currentColumn + tabSize;
496
 
                        return (result / tabSize) * tabSize;
497
 
                }
498
 
 
499
 
                public static void SetFormatOptions (CSharpOutputVisitor outputVisitor, PolicyContainer policyParent)
500
 
                {
501
 
                        IEnumerable<string> types = DesktopService.GetMimeTypeInheritanceChain (MimeType);
502
 
                        TextStylePolicy currentPolicy = policyParent != null ? policyParent.Get<TextStylePolicy> (types) : MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<TextStylePolicy> (types);
503
 
                        CSharpFormattingPolicy codePolicy = policyParent != null ? policyParent.Get<CSharpFormattingPolicy> (types) : MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<CSharpFormattingPolicy> (types);
504
 
 
505
 
                        outputVisitor.Options.IndentationChar = currentPolicy.TabsToSpaces ? ' ' : '\t';
506
 
                        outputVisitor.Options.TabSize = currentPolicy.TabWidth;
507
 
                        outputVisitor.Options.IndentSize = currentPolicy.TabWidth;
508
 
                        outputVisitor.Options.EolMarker = TextStylePolicy.GetEolMarker(currentPolicy.EolMarker);
509
 
 
510
 
                        CodeFormatDescription descr = CSharpFormattingPolicyPanel.CodeFormatDescription;
511
 
                        Type optionType = outputVisitor.Options.GetType ();
512
 
 
513
 
                        foreach (CodeFormatOption option in descr.AllOptions) {
514
 
                                KeyValuePair<string, string> val = descr.GetValue (codePolicy, option);
515
 
                                PropertyInfo info = optionType.GetProperty (option.Name);
516
 
                                if (info == null) {
517
 
                                        System.Console.WriteLine ("option : " + option.Name + " not found.");
518
 
                                        continue;
519
 
                                }
520
 
                                object cval = null;
521
 
                                if (info.PropertyType.IsEnum) {
522
 
                                        cval = Enum.Parse (info.PropertyType, val.Key);
523
 
                                } else if (info.PropertyType == typeof(bool)) {
524
 
                                        cval = Convert.ToBoolean (val.Key);
525
 
                                } else {
526
 
                                        cval = Convert.ChangeType (val.Key, info.PropertyType);
527
 
                                }
528
 
                                //System.Console.WriteLine("set " + option.Name + " to " + cval);
529
 
                                info.SetValue (outputVisitor.Options, cval, null);
530
 
                        }
531
 
                }
532
 
                
533
 
                
534
 
                bool hasErrors = false;
535
 
                int startIndentLevel = 0;
536
 
                protected override string InternalFormat (PolicyContainer policyParent, string mimeType, string input, int startOffset, int endOffset)
537
 
                {
538
 
                        string text = GetFormattedText (policyParent, input);
539
 
                        if (startOffset == 0 && endOffset >= input.Length - 1)
540
 
                                return text;
541
 
                        int newStartOffset = TranslateOffset (input, text, startOffset);
542
 
                        int newEndOffset = TranslateOffset (input, text, endOffset);
543
 
                        if (newStartOffset < 0 || newEndOffset < 0)
544
 
                                return input.Substring (startOffset, System.Math.Max (0, System.Math.Min (endOffset - startOffset, input.Length - startOffset)));
545
 
                        
546
 
                        return text.Substring (newStartOffset, newEndOffset - newStartOffset);
547
 
                }
548
 
 
549
 
                static int TranslateOffset (string baseInput, string formattedInput, int offset)
550
 
                {
551
 
                        int i = 0;
552
 
                        int j = 0;
553
 
                        while (i < baseInput.Length && j < formattedInput.Length && i < offset) {
554
 
                                char ch1 = baseInput[i];
555
 
                                char ch2 = formattedInput[j];
556
 
                                bool ch1IsWs = Char.IsWhiteSpace (ch1);
557
 
                                bool ch2IsWs = Char.IsWhiteSpace (ch2);
558
 
//                              Console.WriteLine ("ch1={0}, ch2={1}, ch1IsWs={2}, ch2IsWs={3}", ch1, ch2, ch1IsWs, ch2IsWs);
559
 
                                if (ch1 == ch2 || ch1IsWs && ch2IsWs) {
560
 
                                        i++;
561
 
                                        j++;
562
 
                                } else if (!ch1IsWs && ch2IsWs) {
563
 
                                        j++;
564
 
                                } else if (ch1IsWs && !ch2IsWs) {
565
 
                                        i++;
566
 
                                } else {
567
 
                                        return -1;
568
 
                                }
569
 
                        }
570
 
                        return j;
571
 
                }
572
 
                
573
 
                string GetFormattedText (PolicyContainer policyParent, string input)
574
 
                {
575
 
                        hasErrors = false;
576
 
                        if (string.IsNullOrEmpty (input))
577
 
                                return input;
578
 
                        
579
 
                        CSharpOutputVisitor outputVisitor = new CSharpOutputVisitor ();
580
 
                        SetFormatOptions (outputVisitor, policyParent);
581
 
                        
582
 
                        outputVisitor.OutputFormatter.IndentationLevel = startIndentLevel;
583
 
                        using (ICSharpCode.NRefactory.IParser parser = ParserFactory.CreateParser (SupportedLanguage.CSharp, new StringReader (input))) {
584
 
                                parser.Parse ();
585
 
                                hasErrors = parser.Errors.Count != 0;
586
 
                //                              if (hasErrors)
587
 
                //                                      Console.WriteLine (parser.Errors.ErrorOutput);
588
 
                                IList<ISpecial> specials = parser.Lexer.SpecialTracker.RetrieveSpecials ();
589
 
                                if (parser.Errors.Count == 0) {
590
 
                                        using (SpecialNodesInserter.Install (specials, outputVisitor)) {
591
 
                                                parser.CompilationUnit.AcceptVisitor (outputVisitor, null);
592
 
                                        }
593
 
                                        return outputVisitor.Text;
594
 
                                }
595
 
                        }
596
 
                        //                      Console.WriteLine ("trying to parse block.");
597
 
                        using (ICSharpCode.NRefactory.IParser parser = ParserFactory.CreateParser (SupportedLanguage.CSharp, new StringReader (input))) {
598
 
                                BlockStatement blockStatement = parser.ParseBlock ();
599
 
                                hasErrors = parser.Errors.Count != 0;
600
 
                                //                              if (hasErrors)
601
 
                                //                                      Console.WriteLine (parser.Errors.ErrorOutput);
602
 
                                IList<ISpecial> specials = parser.Lexer.SpecialTracker.RetrieveSpecials ();
603
 
                                if (parser.Errors.Count == 0) {
604
 
                                        StringBuilder result = new StringBuilder ();
605
 
                                        using (var inserter = SpecialNodesInserter.Install (specials, outputVisitor)) {
606
 
                                                foreach (ICSharpCode.NRefactory.Ast.INode node in blockStatement.Children) {
607
 
                                                        node.AcceptVisitor (outputVisitor, null);
608
 
                                                        //                                                      result.AppendLine (outputVisitor.Text);
609
 
                                                }
610
 
                                                if (!outputVisitor.OutputFormatter.LastCharacterIsNewLine)
611
 
                                                        outputVisitor.OutputFormatter.NewLine ();
612
 
                                                inserter.Finish ();
613
 
                                                result.AppendLine (outputVisitor.Text);
614
 
                                        }
615
 
                                        return result.ToString ();
616
 
                                }
617
 
                        }
618
 
                        //                      Console.WriteLine ("trying to parse expression.");
619
 
                        using (ICSharpCode.NRefactory.IParser parser = ParserFactory.CreateParser (SupportedLanguage.CSharp, new StringReader (input))) {
620
 
                                Expression expression = parser.ParseExpression ();
621
 
                                hasErrors = parser.Errors.Count != 0;
622
 
                                //                              if (hasErrors)
623
 
                                //                                      Console.WriteLine (parser.Errors.ErrorOutput);
624
 
                                IList<ISpecial> specials = parser.Lexer.SpecialTracker.RetrieveSpecials ();
625
 
                                if (parser.Errors.Count == 0) {
626
 
                                        using (SpecialNodesInserter.Install (specials, outputVisitor)) {
627
 
                                                expression.AcceptVisitor (outputVisitor, null);
628
 
                                        }
629
 
                                        return outputVisitor.Text;
630
 
                                }
631
 
                        }
632
 
                        return input;
 
84
 
 
85
                public override void OnTheFlyFormat (PolicyContainer policyParent, IEnumerable<string> mimeTypeChain, 
 
86
                        TextEditorData data, IType type, IMember member, ProjectDom dom, ICompilationUnit unit, DomLocation caretLocation)
 
87
                {
 
88
                        //              OnTheFlyFormatter.Format (policyParent, mimeTypeChain, data, dom, caretLocation, true);
 
89
                }
 
90
 
 
91
                public override void OnTheFlyFormat (PolicyContainer policyParent, IEnumerable<string> mimeTypeChain, 
 
92
                        TextEditorData data, int startOffset, int endOffset)
 
93
                {
 
94
                        var parser = new MonoDevelop.CSharp.Parser.CSharpParser ();
 
95
                        var compilationUnit = parser.Parse (data);
 
96
                        bool hadErrors = parser.HasErrors;
 
97
                        var policy = policyParent.Get<CSharpFormattingPolicy> (mimeTypeChain);
 
98
                        var formattingVisitor = new AstFormattingVisitor (policy, data) {
 
99
                                AutoAcceptChanges = false,
 
100
                                HadErrors = hadErrors
 
101
                        };
 
102
                        compilationUnit.AcceptVisitor (formattingVisitor, null);
 
103
                        
 
104
                        
 
105
                        var changes = new List<Change> ();
 
106
 
 
107
                        changes.AddRange (formattingVisitor.Changes.
 
108
                                Where (c => c is TextReplaceChange && (startOffset <= ((TextReplaceChange)c).Offset && ((TextReplaceChange)c).Offset < endOffset)));
 
109
 
 
110
                        RefactoringService.AcceptChanges (null, null, changes);
 
111
                }
 
112
 
 
113
                public override string FormatText (PolicyContainer policyParent, IEnumerable<string> mimeTypeChain, string input, int startOffset, int endOffset)
 
114
                {
 
115
                        var data = new TextEditorData ();
 
116
                        data.Document.SuppressHighlightUpdate = true;
 
117
                        data.Document.MimeType = mimeTypeChain.First ();
 
118
                        data.Document.FileName = "toformat.cs";
 
119
                        var textPolicy = policyParent.Get<TextStylePolicy> (mimeTypeChain);
 
120
                        data.Options.TabsToSpaces = textPolicy.TabsToSpaces;
 
121
                        data.Options.TabSize = textPolicy.TabWidth;
 
122
                        data.Options.OverrideDocumentEolMarker = true;
 
123
                        data.Options.DefaultEolMarker = textPolicy.GetEolMarker ();
 
124
                        data.Text = input;
 
125
 
 
126
//                      System.Console.WriteLine ("-----");
 
127
//                      System.Console.WriteLine (data.Text.Replace (" ", ".").Replace ("\t", "->"));
 
128
//                      System.Console.WriteLine ("-----");
 
129
 
 
130
                        MonoDevelop.CSharp.Parser.CSharpParser parser = new MonoDevelop.CSharp.Parser.CSharpParser ();
 
131
                        var compilationUnit = parser.Parse (data);
 
132
                        bool hadErrors = parser.HasErrors;
 
133
                        if (hadErrors) {
 
134
//                              foreach (var e in parser.ErrorReportPrinter.Errors)
 
135
//                                      Console.WriteLine (e.Message);
 
136
                                return input.Substring (startOffset, Math.Max (0, Math.Min (endOffset, input.Length) - startOffset));
 
137
                        }
 
138
                        var policy = policyParent.Get<CSharpFormattingPolicy> (mimeTypeChain);
 
139
 
 
140
                        var formattingVisitor = new AstFormattingVisitor (policy, data) {
 
141
                                AutoAcceptChanges = false,
 
142
                                HadErrors = hadErrors
 
143
                        };
 
144
                        compilationUnit.AcceptVisitor (formattingVisitor, null);
 
145
 
 
146
                        var changes = new List<Change> ();
 
147
 
 
148
                        changes.AddRange (formattingVisitor.Changes.
 
149
                                Where (c => c is TextReplaceChange && (startOffset <= ((TextReplaceChange)c).Offset && ((TextReplaceChange)c).Offset < endOffset)));
 
150
 
 
151
                        RefactoringService.AcceptChanges (null, null, changes);
 
152
                        int end = endOffset;
 
153
                        foreach (TextReplaceChange c in changes) {
 
154
                                end -= c.RemovedChars;
 
155
                                if (c.InsertedText != null)
 
156
                                        end += c.InsertedText.Length;
 
157
                        }
 
158
                        /*                      System.Console.WriteLine ("-----");
 
159
                        System.Console.WriteLine (data.Text.Replace (" ", "^").Replace ("\t", "->"));
 
160
                        System.Console.WriteLine ("-----");*/
 
161
                        string result = data.GetTextBetween (startOffset, Math.Min (data.Length, end));
 
162
                        data.Dispose ();
 
163
                        return result;
633
164
                }
634
165
        }
635
166
}