1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
5
using System.Collections.Generic;
6
using ICSharpCode.Core;
7
using ICSharpCode.NRefactory;
9
namespace ICSharpCode.SharpDevelop.Editor
12
/// Read-only implementation of IDocument.
14
sealed class ReadOnlyDocument : IDocument
16
ITextBuffer textBuffer;
19
public ReadOnlyDocument(ITextBuffer textBuffer)
21
if (textBuffer == null)
22
throw new ArgumentNullException("textBuffer");
23
// ensure that underlying buffer is immutable
24
this.textBuffer = textBuffer.CreateSnapshot();
25
List<int> lines = new List<int>();
29
var textSource = DocumentUtilitites.GetTextSource(this.textBuffer);
30
while ((offset = ICSharpCode.AvalonEdit.Document.TextUtilities.FindNextNewLine(textSource, offset, out newlineType)) >= 0) {
31
offset += newlineType.Length;
34
this.lines = lines.ToArray();
37
public IDocumentLine GetLine(int lineNumber)
39
if (lineNumber < 1 || lineNumber > lines.Length)
40
throw new ArgumentOutOfRangeException("lineNumber", lineNumber, "Value must be between 1 and " + lines.Length);
41
return new ReadOnlyDocumentLine(this, lineNumber);
44
sealed class ReadOnlyDocumentLine : IDocumentLine
46
readonly ReadOnlyDocument doc;
47
readonly int lineNumber;
48
readonly int offset, endOffset;
50
public ReadOnlyDocumentLine(ReadOnlyDocument doc, int lineNumber)
53
this.lineNumber = lineNumber;
54
this.offset = doc.GetStartOffset(lineNumber);
55
this.endOffset = doc.GetEndOffset(lineNumber);
59
get { return offset; }
63
get { return endOffset - offset; }
66
public int EndOffset {
67
get { return endOffset; }
70
public int TotalLength {
72
return doc.GetTotalEndOffset(lineNumber) - offset;
76
public int DelimiterLength {
78
return doc.GetTotalEndOffset(lineNumber) - endOffset;
82
public int LineNumber {
83
get { return lineNumber; }
88
return doc.GetText(this.Offset, this.Length);
93
int GetStartOffset(int lineNumber)
95
return lines[lineNumber-1];
98
int GetTotalEndOffset(int lineNumber)
100
return lineNumber < lines.Length ? lines[lineNumber] : textBuffer.TextLength;
103
int GetEndOffset(int lineNumber)
105
if (lineNumber == lines.Length)
106
return textBuffer.TextLength;
107
int off = lines[lineNumber] - 1;
108
if (off > 0 && textBuffer.GetCharAt(off - 1) == '\r' && textBuffer.GetCharAt(off) == '\n')
113
public IDocumentLine GetLineForOffset(int offset)
115
return GetLine(GetLineNumberForOffset(offset));
118
int GetLineNumberForOffset(int offset)
120
int r = Array.BinarySearch(lines, offset);
121
return r < 0 ? ~r : r + 1;
124
public int PositionToOffset(int line, int column)
126
if (line < 1 || line > lines.Length)
127
throw new ArgumentOutOfRangeException("line", line, "Value must be between 1 and " + lines.Length);
128
int lineStart = GetStartOffset(line);
131
int lineEnd = GetEndOffset(line);
132
if (column >= lineEnd - lineStart)
134
return lineStart + column - 1;
137
public Location OffsetToPosition(int offset)
139
if (offset < 0 || offset > textBuffer.TextLength)
140
throw new ArgumentOutOfRangeException("offset", offset, "Value must be between 0 and " + textBuffer.TextLength);
141
int line = GetLineNumberForOffset(offset);
142
return new Location(offset-GetStartOffset(line)+1, line);
145
public event EventHandler<TextChangeEventArgs> Changing { add {} remove {} }
147
public event EventHandler<TextChangeEventArgs> Changed { add {} remove {} }
149
public event EventHandler TextChanged { add {} remove {} }
152
get { return textBuffer.Text; }
154
throw new NotSupportedException();
158
public int TotalNumberOfLines {
159
get { return lines.Length; }
162
public ITextBufferVersion Version {
166
public int TextLength {
167
get { return textBuffer.TextLength; }
170
void IDocument.Insert(int offset, string text)
172
throw new NotSupportedException();
175
void IDocument.Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType)
177
throw new NotSupportedException();
180
void IDocument.Remove(int offset, int length)
182
throw new NotSupportedException();
185
void IDocument.Replace(int offset, int length, string newText)
187
throw new NotSupportedException();
190
public void StartUndoableAction()
194
public void EndUndoableAction()
198
public IDisposable OpenUndoGroup()
200
return new CallbackOnDispose(EndUndoableAction);
203
public ITextAnchor CreateAnchor(int offset)
205
return new ReadOnlyDocumentTextAnchor(OffsetToPosition(offset), offset);
208
sealed class ReadOnlyDocumentTextAnchor : ITextAnchor
210
readonly Location location;
213
public ReadOnlyDocumentTextAnchor(Location location, int offset)
215
this.location = location;
216
this.offset = offset;
219
public event EventHandler Deleted { add {} remove {} }
221
public Location Location {
222
get { return location; }
226
get { return offset; }
229
public AnchorMovementType MovementType { get; set; }
231
public bool SurviveDeletion { get; set; }
233
public bool IsDeleted {
234
get { return false; }
238
get { return location.Line; }
242
get { return location.Column; }
246
public ITextBuffer CreateSnapshot()
248
return textBuffer; // textBuffer is immutable
251
public ITextBuffer CreateSnapshot(int offset, int length)
253
return textBuffer.CreateSnapshot(offset, length);
256
public System.IO.TextReader CreateReader()
258
return textBuffer.CreateReader();
261
public System.IO.TextReader CreateReader(int offset, int length)
263
return textBuffer.CreateReader(offset, length);
266
public char GetCharAt(int offset)
268
return textBuffer.GetCharAt(offset);
271
public string GetText(int offset, int length)
273
return textBuffer.GetText(offset, length);
276
public object GetService(Type serviceType)