Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CodeEditor/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory-5.5.0/Editor/ReadOnlyDocument.cs @ 11700

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

#2077: created branch and added first version

File size: 11.1 KB
Line 
1// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Collections.Generic;
21
22namespace ICSharpCode.NRefactory.Editor
23{
24  /// <summary>
25  /// Read-only implementation of <see cref="IDocument"/>.
26  /// </summary>
27  [Serializable]
28  public sealed class ReadOnlyDocument : IDocument
29  {
30    readonly ITextSource textSource;
31    readonly string fileName;
32    int[] lines;
33   
34    static readonly char[] newline = { '\r', '\n' };
35   
36    /// <summary>
37    /// Creates a new ReadOnlyDocument from the given text source.
38    /// </summary>
39    public ReadOnlyDocument(ITextSource textSource)
40    {
41      if (textSource == null)
42        throw new ArgumentNullException("textSource");
43      // ensure that underlying buffer is immutable
44      this.textSource = textSource.CreateSnapshot();
45      List<int> lines = new List<int>();
46      lines.Add(0);
47      int offset = 0;
48      int textLength = textSource.TextLength;
49      while ((offset = textSource.IndexOfAny(newline, offset, textLength - offset)) >= 0) {
50        offset++;
51        if (textSource.GetCharAt(offset - 1) == '\r' && offset < textLength && textSource.GetCharAt(offset) == '\n') {
52          offset++;
53        }
54        lines.Add(offset);
55      }
56      this.lines = lines.ToArray();
57    }
58   
59    /// <summary>
60    /// Creates a new ReadOnlyDocument from the given string.
61    /// </summary>
62    public ReadOnlyDocument(string text)
63      : this(new StringTextSource(text))
64    {
65    }
66   
67    /// <summary>
68    /// Creates a new ReadOnlyDocument from the given text source;
69    /// and sets IDocument.FileName to the specified file name.
70    /// </summary>
71    public ReadOnlyDocument(ITextSource textSource, string fileName)
72      : this(textSource)
73    {
74      this.fileName = fileName;
75    }
76   
77    /// <inheritdoc/>
78    public IDocumentLine GetLineByNumber(int lineNumber)
79    {
80      if (lineNumber < 1 || lineNumber > lines.Length)
81        throw new ArgumentOutOfRangeException("lineNumber", lineNumber, "Value must be between 1 and " + lines.Length);
82      return new ReadOnlyDocumentLine(this, lineNumber);
83    }
84   
85    sealed class ReadOnlyDocumentLine : IDocumentLine
86    {
87      readonly ReadOnlyDocument doc;
88      readonly int lineNumber;
89      readonly int offset, endOffset;
90     
91      public ReadOnlyDocumentLine(ReadOnlyDocument doc, int lineNumber)
92      {
93        this.doc = doc;
94        this.lineNumber = lineNumber;
95        this.offset = doc.GetStartOffset(lineNumber);
96        this.endOffset = doc.GetEndOffset(lineNumber);
97      }
98     
99      public override int GetHashCode()
100      {
101        return doc.GetHashCode() ^ lineNumber;
102      }
103     
104      public override bool Equals(object obj)
105      {
106        ReadOnlyDocumentLine other = obj as ReadOnlyDocumentLine;
107        return other != null && doc == other.doc && lineNumber == other.lineNumber;
108      }
109     
110      public int Offset {
111        get { return offset; }
112      }
113     
114      public int Length {
115        get { return endOffset - offset; }
116      }
117     
118      public int EndOffset {
119        get { return endOffset; }
120      }
121     
122      public int TotalLength {
123        get {
124          return doc.GetTotalEndOffset(lineNumber) - offset;
125        }
126      }
127     
128      public int DelimiterLength {
129        get {
130          return doc.GetTotalEndOffset(lineNumber) - endOffset;
131        }
132      }
133     
134      public int LineNumber {
135        get { return lineNumber; }
136      }
137     
138      public IDocumentLine PreviousLine {
139        get {
140          if (lineNumber == 1)
141            return null;
142          else
143            return new ReadOnlyDocumentLine(doc, lineNumber - 1);
144        }
145      }
146     
147      public IDocumentLine NextLine {
148        get {
149          if (lineNumber == doc.LineCount)
150            return null;
151          else
152            return new ReadOnlyDocumentLine(doc, lineNumber + 1);
153        }
154      }
155     
156      public bool IsDeleted {
157        get { return false; }
158      }
159    }
160   
161    int GetStartOffset(int lineNumber)
162    {
163      return lines[lineNumber-1];
164    }
165   
166    int GetTotalEndOffset(int lineNumber)
167    {
168      return lineNumber < lines.Length ? lines[lineNumber] : textSource.TextLength;
169    }
170   
171    int GetEndOffset(int lineNumber)
172    {
173      if (lineNumber == lines.Length)
174        return textSource.TextLength;
175      int off = lines[lineNumber] - 1;
176      if (off > 0 && textSource.GetCharAt(off - 1) == '\r' && textSource.GetCharAt(off) == '\n')
177        off--;
178      return off;
179    }
180   
181    /// <inheritdoc/>
182    public IDocumentLine GetLineByOffset(int offset)
183    {
184      return GetLineByNumber(GetLineNumberForOffset(offset));
185    }
186   
187    int GetLineNumberForOffset(int offset)
188    {
189      int r = Array.BinarySearch(lines, offset);
190      return r < 0 ? ~r : r + 1;
191    }
192   
193    /// <inheritdoc/>
194    public int GetOffset(int line, int column)
195    {
196      if (line < 1 || line > lines.Length)
197        throw new ArgumentOutOfRangeException("line", line, "Value must be between 1 and " + lines.Length);
198      int lineStart = GetStartOffset(line);
199      if (column <= 1)
200        return lineStart;
201      int lineEnd = GetEndOffset(line);
202      if (column - 1 >= lineEnd - lineStart)
203        return lineEnd;
204      return lineStart + column - 1;
205    }
206   
207    /// <inheritdoc/>
208    public int GetOffset(TextLocation location)
209    {
210      return GetOffset(location.Line, location.Column);
211    }
212   
213    /// <inheritdoc/>
214    public TextLocation GetLocation(int offset)
215    {
216      if (offset < 0 || offset > textSource.TextLength)
217        throw new ArgumentOutOfRangeException("offset", offset, "Value must be between 0 and " + textSource.TextLength);
218      int line = GetLineNumberForOffset(offset);
219      return new TextLocation(line, offset-GetStartOffset(line)+1);
220    }
221   
222    /// <inheritdoc/>
223    public string Text {
224      get { return textSource.Text; }
225      set {
226        throw new NotSupportedException();
227      }
228    }
229   
230    /// <inheritdoc/>
231    public int LineCount {
232      get { return lines.Length; }
233    }
234   
235    /// <inheritdoc/>
236    public ITextSourceVersion Version {
237      get { return textSource.Version; }
238    }
239   
240    /// <inheritdoc/>
241    public int TextLength {
242      get { return textSource.TextLength; }
243    }
244   
245    event EventHandler<TextChangeEventArgs> IDocument.TextChanging { add {} remove {} }
246   
247    event EventHandler<TextChangeEventArgs> IDocument.TextChanged { add {} remove {} }
248   
249    event EventHandler IDocument.ChangeCompleted { add {} remove {} }
250   
251    void IDocument.Insert(int offset, string text)
252    {
253      throw new NotSupportedException();
254    }
255   
256    void IDocument.Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType)
257    {
258      throw new NotSupportedException();
259    }
260   
261    void IDocument.Remove(int offset, int length)
262    {
263      throw new NotSupportedException();
264    }
265   
266    void IDocument.Replace(int offset, int length, string newText)
267    {
268      throw new NotSupportedException();
269    }
270   
271    void IDocument.Insert(int offset, ITextSource text)
272    {
273      throw new NotSupportedException();
274    }
275   
276    void IDocument.Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType)
277    {
278      throw new NotSupportedException();
279    }
280   
281    void IDocument.Replace(int offset, int length, ITextSource newText)
282    {
283      throw new NotSupportedException();
284    }
285   
286    void IDocument.StartUndoableAction()
287    {
288    }
289   
290    void IDocument.EndUndoableAction()
291    {
292    }
293   
294    IDisposable IDocument.OpenUndoGroup()
295    {
296      return null;
297    }
298   
299    /// <inheritdoc/>
300    public ITextAnchor CreateAnchor(int offset)
301    {
302      return new ReadOnlyDocumentTextAnchor(GetLocation(offset), offset);
303    }
304   
305    sealed class ReadOnlyDocumentTextAnchor : ITextAnchor
306    {
307      readonly TextLocation location;
308      readonly int offset;
309     
310      public ReadOnlyDocumentTextAnchor(TextLocation location, int offset)
311      {
312        this.location = location;
313        this.offset = offset;
314      }
315     
316      public event EventHandler Deleted { add {} remove {} }
317     
318      public TextLocation Location {
319        get { return location; }
320      }
321     
322      public int Offset {
323        get { return offset; }
324      }
325     
326      public AnchorMovementType MovementType { get; set; }
327     
328      public bool SurviveDeletion { get; set; }
329     
330      public bool IsDeleted {
331        get { return false; }
332      }
333     
334      public int Line {
335        get { return location.Line; }
336      }
337     
338      public int Column {
339        get { return location.Column; }
340      }
341    }
342   
343    /// <inheritdoc/>
344    public ITextSource CreateSnapshot()
345    {
346      return textSource; // textBuffer is immutable
347    }
348   
349    /// <inheritdoc/>
350    public ITextSource CreateSnapshot(int offset, int length)
351    {
352      return textSource.CreateSnapshot(offset, length);
353    }
354   
355    /// <inheritdoc/>
356    public IDocument CreateDocumentSnapshot()
357    {
358      return this; // ReadOnlyDocument is immutable
359    }
360   
361    /// <inheritdoc/>
362    public System.IO.TextReader CreateReader()
363    {
364      return textSource.CreateReader();
365    }
366   
367    /// <inheritdoc/>
368    public System.IO.TextReader CreateReader(int offset, int length)
369    {
370      return textSource.CreateReader(offset, length);
371    }
372   
373    /// <inheritdoc/>
374    public void WriteTextTo(System.IO.TextWriter writer)
375    {
376      textSource.WriteTextTo(writer);
377    }
378   
379    /// <inheritdoc/>
380    public void WriteTextTo(System.IO.TextWriter writer, int offset, int length)
381    {
382      textSource.WriteTextTo(writer, offset, length);
383    }
384   
385    /// <inheritdoc/>
386    public char GetCharAt(int offset)
387    {
388      return textSource.GetCharAt(offset);
389    }
390   
391    /// <inheritdoc/>
392    public string GetText(int offset, int length)
393    {
394      return textSource.GetText(offset, length);
395    }
396   
397    /// <inheritdoc/>
398    public string GetText(ISegment segment)
399    {
400      return textSource.GetText(segment);
401    }
402   
403    /// <inheritdoc/>
404    public int IndexOf(char c, int startIndex, int count)
405    {
406      return textSource.IndexOf(c, startIndex, count);
407    }
408   
409    /// <inheritdoc/>
410    public int IndexOfAny(char[] anyOf, int startIndex, int count)
411    {
412      return textSource.IndexOfAny(anyOf, startIndex, count);
413    }
414   
415    /// <inheritdoc/>
416    public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
417    {
418      return textSource.IndexOf(searchText, startIndex, count, comparisonType);
419    }
420   
421    /// <inheritdoc/>
422    public int LastIndexOf(char c, int startIndex, int count)
423    {
424      return textSource.LastIndexOf(c, startIndex, count);
425    }
426   
427    /// <inheritdoc/>
428    public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
429    {
430      return textSource.LastIndexOf(searchText, startIndex, count, comparisonType);
431    }
432   
433    object IServiceProvider.GetService(Type serviceType)
434    {
435      return null;
436    }
437   
438    /// <inheritdoc/>
439    /// <remarks>Will never be raised on <see cref="ReadOnlyDocument" />.</remarks>
440    public event EventHandler FileNameChanged { add {} remove {} }
441   
442    /// <inheritdoc/>
443    public string FileName {
444      get { return fileName; }
445    }
446  }
447}
Note: See TracBrowser for help on using the repository browser.