Browse Source

Detect when newlines are inconsistent and allow user to fix them.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5747 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Daniel Grunwald 16 years ago
parent
commit
6e0521b88c
  1. 1
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj
  2. 2
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
  3. 142
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/NewLineConsistencyCheck.cs
  4. 54
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLine.cs
  5. 11
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLineTree.cs
  6. 16
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineManager.cs
  7. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs
  8. 53
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs
  9. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs
  10. 22
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs
  11. 8
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
  12. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs
  13. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
  14. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs
  15. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/InsertionContext.cs
  16. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs

1
src/AddIns/DisplayBindings/AvalonEdit.AddIn/AvalonEdit.AddIn.csproj

@ -89,6 +89,7 @@
<Compile Include="Src\CodeEditorAdapter.cs" /> <Compile Include="Src\CodeEditorAdapter.cs" />
<Compile Include="Src\CodeEditorView.cs" /> <Compile Include="Src\CodeEditorView.cs" />
<Compile Include="Src\ExpressionHighlightRenderer.cs" /> <Compile Include="Src\ExpressionHighlightRenderer.cs" />
<Compile Include="Src\NewLineConsistencyCheck.cs" />
<Compile Include="Src\SharpDevelopTextEditor.cs" /> <Compile Include="Src\SharpDevelopTextEditor.cs" />
<Compile Include="Src\Commands\FoldingCommands.cs" /> <Compile Include="Src\Commands\FoldingCommands.cs" />
<Compile Include="Src\Commands\RunIncrementalSearch.cs" /> <Compile Include="Src\Commands\RunIncrementalSearch.cs" />

2
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs

@ -11,6 +11,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
@ -284,6 +285,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
this.Encoding = reader.CurrentEncoding; this.Encoding = reader.CurrentEncoding;
} }
} }
NewLineConsistencyCheck.StartConsistencyCheck(this);
} }
public void Save(Stream stream) public void Save(Stream stream)

142
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/NewLineConsistencyCheck.cs

@ -0,0 +1,142 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <author name="Daniel Grunwald"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.Core;
namespace ICSharpCode.AvalonEdit.AddIn
{
/// <summary>
/// Description of NewLineConsistencyCheck.
/// </summary>
public class NewLineConsistencyCheck
{
public static void StartConsistencyCheck(CodeEditor editor)
{
NewLineConsistencyCheck c = new NewLineConsistencyCheck(editor);
ThreadPool.QueueUserWorkItem(c.CheckNewLinesForConsistency);
}
CodeEditor editor;
ITextSource snapshot;
private NewLineConsistencyCheck(CodeEditor editor)
{
this.editor = editor;
this.snapshot = editor.Document.CreateSnapshot();
}
void CheckNewLinesForConsistency(object state)
{
int numCRLF = 0;
int numCR = 0;
int numLF = 0;
int offset = 0;
while (offset >= 0) {
string type;
offset = TextUtilities.FindNextNewLine(snapshot, offset, out type);
if (type != null) {
offset += type.Length;
switch (type) {
case "\r\n":
numCRLF++;
break;
case "\n":
numLF++;
break;
case "\r":
numCR++;
break;
}
}
}
snapshot = null; // we don't need the snapshot anymore, allow the GC to collect it
// don't allow mac-style newlines; accept either unix or windows-style newlines but avoid mixing them
bool isConsistent = (numCR == 0) && (numLF == 0 || numCRLF == 0);
if (!isConsistent) {
SharpDevelop.Gui.WorkbenchSingleton.SafeThreadAsyncCall(ShowInconsistentWarning, numLF > numCRLF);
}
}
GroupBox groupBox;
Button normalizeButton, cancelButton;
RadioButton windows, unix;
void ShowInconsistentWarning(bool preferUnixNewLines)
{
if (editor.Document == null)
return; // editor was disposed
// TODO: translate
groupBox = new GroupBox();
groupBox.Background = SystemColors.WindowBrush;
groupBox.Foreground = SystemColors.WindowTextBrush;
groupBox.Header = "Inconsistent NewLines";
groupBox.HorizontalAlignment = HorizontalAlignment.Right;
groupBox.VerticalAlignment = VerticalAlignment.Bottom;
groupBox.MaxWidth = 300;
groupBox.Margin = new Thickness(0, 0, 20, 20);
Grid.SetRow(groupBox, 1);
windows = new RadioButton {
IsChecked = !preferUnixNewLines,
Content = ResourceService.GetString("Dialog.Options.IDEOptions.LoadSaveOptions.WindowsRadioButton"),
Margin = new Thickness(0, 0, 8, 0)
};
unix = new RadioButton {
IsChecked = preferUnixNewLines,
Content = ResourceService.GetString("Dialog.Options.IDEOptions.LoadSaveOptions.UnixRadioButton")
};
normalizeButton = new Button { Content = "Normalize" };
cancelButton = new Button { Content = ResourceService.GetString("Global.CancelButtonText") };
groupBox.Content = new StackPanel {
Children = {
new TextBlock { Text = "This file contains inconsistent newlines.", TextWrapping = TextWrapping.WrapWithOverflow },
windows, unix,
new StackPanel {
Margin = new Thickness(0, 2, 0, 0),
Orientation = Orientation.Horizontal,
Children = { normalizeButton, cancelButton }
}
}
};
editor.Children.Add(groupBox);
cancelButton.Click += delegate {
editor.Children.Remove(groupBox);
editor.PrimaryTextEditor.TextArea.Focus();
};
normalizeButton.Click += delegate {
editor.Children.Remove(groupBox);
editor.PrimaryTextEditor.TextArea.Focus();
TextDocument document = editor.Document;
string newNewLine = (unix.IsChecked == true) ? "\n" : "\r\n";
using (document.RunUpdate()) {
for (int i = 1; i <= document.LineCount; i++) {
// re-fetch DocumentLine for every iteration because we're modifying the newlines so that DocumentLines might get re-created
DocumentLine line = document.GetLineByNumber(i);
if (line.DelimiterLength > 0) {
int endOffset = line.EndOffset;
if (document.GetText(endOffset, line.DelimiterLength) != newNewLine)
document.Replace(endOffset, line.DelimiterLength, newNewLine);
}
}
}
};
}
}
}

54
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLine.cs

@ -29,42 +29,28 @@ namespace ICSharpCode.AvalonEdit.Document
public sealed partial class DocumentLine : ISegment public sealed partial class DocumentLine : ISegment
{ {
#region Constructor #region Constructor
internal readonly TextDocument document; #if DEBUG
// Required for thread safety check which is done only in debug builds.
// To save space, we don't store the document reference in release builds as we don't need it there.
readonly TextDocument document;
#endif
internal bool isDeleted; internal bool isDeleted;
internal DocumentLine(TextDocument document) internal DocumentLine(TextDocument document)
{ {
#if DEBUG
Debug.Assert(document != null); Debug.Assert(document != null);
this.document = document; this.document = document;
} #endif
#endregion
#region Document / Text
/// <summary>
/// Gets the text document that owns this DocumentLine. O(1).
/// </summary>
/// <remarks>This property is still available even if the line was deleted.</remarks>
[ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. " +
"It will be removed in a future AvalonEdit version.")]
public TextDocument Document {
get {
document.DebugVerifyAccess();
return document;
}
} }
[Conditional("DEBUG")]
/// <summary> void DebugVerifyAccess()
/// Gets the text on this line. {
/// </summary> #if DEBUG
/// <exception cref="InvalidOperationException">The line was deleted.</exception> document.DebugVerifyAccess();
[ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. " + #endif
"It will be removed in a future AvalonEdit version. " +
"Use 'document.GetText(documentLine)' instead.")]
public string Text {
get {
return document.GetText(this.Offset, this.Length);
}
} }
#endregion #endregion
@ -100,7 +86,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary> /// </summary>
public bool IsDeleted { public bool IsDeleted {
get { get {
document.DebugVerifyAccess(); DebugVerifyAccess();
return isDeleted; return isDeleted;
} }
} }
@ -153,7 +139,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// in that case, it contains the line's length before the deletion.</remarks> /// in that case, it contains the line's length before the deletion.</remarks>
public int Length { public int Length {
get { get {
document.DebugVerifyAccess(); DebugVerifyAccess();
return totalLength - delimiterLength; return totalLength - delimiterLength;
} }
} }
@ -165,7 +151,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// in that case, it contains the line's length before the deletion.</remarks> /// in that case, it contains the line's length before the deletion.</remarks>
public int TotalLength { public int TotalLength {
get { get {
document.DebugVerifyAccess(); DebugVerifyAccess();
return totalLength; return totalLength;
} }
internal set { internal set {
@ -183,7 +169,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// in that case, it contains the line delimiter's length before the deletion.</remarks> /// in that case, it contains the line delimiter's length before the deletion.</remarks>
public int DelimiterLength { public int DelimiterLength {
get { get {
document.DebugVerifyAccess(); DebugVerifyAccess();
return delimiterLength; return delimiterLength;
} }
internal set { internal set {
@ -200,7 +186,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <returns>The line following this line, or null if this is the last line.</returns> /// <returns>The line following this line, or null if this is the last line.</returns>
public DocumentLine NextLine { public DocumentLine NextLine {
get { get {
document.DebugVerifyAccess(); DebugVerifyAccess();
if (right != null) { if (right != null) {
return right.LeftMost; return right.LeftMost;
@ -223,7 +209,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <returns>The line before this line, or null if this is the first line.</returns> /// <returns>The line before this line, or null if this is the first line.</returns>
public DocumentLine PreviousLine { public DocumentLine PreviousLine {
get { get {
document.DebugVerifyAccess(); DebugVerifyAccess();
if (left != null) { if (left != null) {
return left.RightMost; return left.RightMost;

11
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLineTree.cs

@ -638,10 +638,13 @@ namespace ICSharpCode.AvalonEdit.Document
int IList<DocumentLine>.IndexOf(DocumentLine item) int IList<DocumentLine>.IndexOf(DocumentLine item)
{ {
document.VerifyAccess(); document.VerifyAccess();
if (item == null || item.document != document || item.IsDeleted) if (item == null || item.IsDeleted)
return -1; return -1;
int index = item.LineNumber - 1;
if (index < LineCount && GetNodeByIndex(index) == item)
return index;
else else
return item.LineNumber - 1; return -1;
} }
void IList<DocumentLine>.Insert(int index, DocumentLine item) void IList<DocumentLine>.Insert(int index, DocumentLine item)
@ -666,8 +669,8 @@ namespace ICSharpCode.AvalonEdit.Document
bool ICollection<DocumentLine>.Contains(DocumentLine item) bool ICollection<DocumentLine>.Contains(DocumentLine item)
{ {
document.VerifyAccess(); IList<DocumentLine> self = this;
return item != null && item.document == document && !item.IsDeleted; return self.IndexOf(item) >= 0;
} }
void ICollection<DocumentLine>.CopyTo(DocumentLine[] array, int arrayIndex) void ICollection<DocumentLine>.CopyTo(DocumentLine[] array, int arrayIndex)

16
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineManager.cs

@ -20,7 +20,6 @@ namespace ICSharpCode.AvalonEdit.Document
{ {
#region Constructor #region Constructor
readonly TextDocument document; readonly TextDocument document;
readonly IList<char> textBuffer;
readonly DocumentLineTree documentLineTree; readonly DocumentLineTree documentLineTree;
/// <summary> /// <summary>
@ -34,10 +33,9 @@ namespace ICSharpCode.AvalonEdit.Document
this.lineTrackers = document.LineTrackers.ToArray(); this.lineTrackers = document.LineTrackers.ToArray();
} }
public LineManager(IList<char> textBuffer, DocumentLineTree documentLineTree, TextDocument document) public LineManager(DocumentLineTree documentLineTree, TextDocument document)
{ {
this.document = document; this.document = document;
this.textBuffer = textBuffer;
this.documentLineTree = documentLineTree; this.documentLineTree = documentLineTree;
UpdateListOfLineTrackers(); UpdateListOfLineTrackers();
@ -95,7 +93,7 @@ namespace ICSharpCode.AvalonEdit.Document
{ {
// keep the first document line // keep the first document line
DocumentLine ls = documentLineTree.GetByNumber(1); DocumentLine ls = documentLineTree.GetByNumber(1);
SimpleSegment ds = NewLineFinder.NextNewLine(textBuffer, 0); SimpleSegment ds = NewLineFinder.NextNewLine(document, 0);
List<DocumentLine> lines = new List<DocumentLine>(); List<DocumentLine> lines = new List<DocumentLine>();
int lastDelimiterEnd = 0; int lastDelimiterEnd = 0;
while (ds != SimpleSegment.Invalid) { while (ds != SimpleSegment.Invalid) {
@ -105,10 +103,10 @@ namespace ICSharpCode.AvalonEdit.Document
lines.Add(ls); lines.Add(ls);
ls = new DocumentLine(document); ls = new DocumentLine(document);
ds = NewLineFinder.NextNewLine(textBuffer, lastDelimiterEnd); ds = NewLineFinder.NextNewLine(document, lastDelimiterEnd);
} }
ls.ResetLine(); ls.ResetLine();
ls.TotalLength = textBuffer.Count - lastDelimiterEnd; ls.TotalLength = document.TextLength - lastDelimiterEnd;
lines.Add(ls); lines.Add(ls);
documentLineTree.RebuildTree(lines); documentLineTree.RebuildTree(lines);
foreach (ILineTracker lineTracker in lineTrackers) foreach (ILineTracker lineTracker in lineTrackers)
@ -269,13 +267,13 @@ namespace ICSharpCode.AvalonEdit.Document
line.DelimiterLength = 0; line.DelimiterLength = 0;
} else { } else {
int lineOffset = line.Offset; int lineOffset = line.Offset;
char lastChar = textBuffer[lineOffset + newTotalLength - 1]; char lastChar = document.GetCharAt(lineOffset + newTotalLength - 1);
if (lastChar == '\r') { if (lastChar == '\r') {
line.DelimiterLength = 1; line.DelimiterLength = 1;
} else if (lastChar == '\n') { } else if (lastChar == '\n') {
if (newTotalLength >= 2 && textBuffer[lineOffset + newTotalLength - 2] == '\r') { if (newTotalLength >= 2 && document.GetCharAt(lineOffset + newTotalLength - 2) == '\r') {
line.DelimiterLength = 2; line.DelimiterLength = 2;
} else if (newTotalLength == 1 && lineOffset > 0 && textBuffer[lineOffset - 1] == '\r') { } else if (newTotalLength == 1 && lineOffset > 0 && document.GetCharAt(lineOffset - 1) == '\r') {
// we need to join this line with the previous line // we need to join this line with the previous line
DocumentLine previousLine = line.PreviousLine; DocumentLine previousLine = line.PreviousLine;
RemoveLine(line); RemoveLine(line);

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs

@ -29,12 +29,11 @@ namespace ICSharpCode.AvalonEdit.Document
// actually increased the memory requirements. The JIT packs two bools and a byte (delimiterSize) // actually increased the memory requirements. The JIT packs two bools and a byte (delimiterSize)
// into a single DWORD, but two bytes get each their own DWORD. Three bytes end up in the same DWORD, so // into a single DWORD, but two bytes get each their own DWORD. Three bytes end up in the same DWORD, so
// apparently the JIT only optimizes for memory when there are at least three small fields. // apparently the JIT only optimizes for memory when there are at least three small fields.
// Currently, DocumentLine takes 40 bytes on x86 (8 byte object overhead, 4 pointers, 3 ints, and another DWORD // Currently, DocumentLine takes 36 bytes on x86 (8 byte object overhead, 3 pointers, 3 ints, and another DWORD
// for the small fields). // for the small fields).
// TODO: a possible optimization would be to combine 'totalLength' and the small fields into a single uint. // TODO: a possible optimization would be to combine 'totalLength' and the small fields into a single uint.
// delimiterSize takes only two bits, the two bools take another two bits; so there's still // delimiterSize takes only two bits, the two bools take another two bits; so there's still
// 28 bits left for totalLength. 268435455 characters per line should be enough for everyone :) // 28 bits left for totalLength. 268435455 characters per line should be enough for everyone :)
// TODO: remove the 'document' pointer in release builds
/// <summary> /// <summary>
/// Resets the line to enable its reuse after a document rebuild. /// Resets the line to enable its reuse after a document rebuild.

53
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs

@ -12,16 +12,13 @@ using System.Text;
namespace ICSharpCode.AvalonEdit.Document namespace ICSharpCode.AvalonEdit.Document
{ {
/// <summary>
/// Helper methods for finding new lines.
/// </summary>
static class NewLineFinder static class NewLineFinder
{ {
/// <summary> /// <summary>
/// Gets the location of the next new line character, or SimpleSegment.Invalid /// Gets the location of the next new line character, or SimpleSegment.Invalid
/// if none is found. /// if none is found.
/// </summary> /// </summary>
public static SimpleSegment NextNewLine(string text, int offset) internal static SimpleSegment NextNewLine(string text, int offset)
{ {
for (int i = offset; i < text.Length; i++) { for (int i = offset; i < text.Length; i++) {
switch (text[i]) { switch (text[i]) {
@ -43,14 +40,14 @@ namespace ICSharpCode.AvalonEdit.Document
/// Gets the location of the next new line character, or SimpleSegment.Invalid /// Gets the location of the next new line character, or SimpleSegment.Invalid
/// if none is found. /// if none is found.
/// </summary> /// </summary>
public static SimpleSegment NextNewLine(IList<char> text, int offset) internal static SimpleSegment NextNewLine(ITextSource text, int offset)
{ {
int textLength = text.Count; int textLength = text.TextLength;
for (int i = offset; i < textLength; i++) { for (int i = offset; i < textLength; i++) {
switch (text[i]) { switch (text.GetCharAt(i)) {
case '\r': case '\r':
if (i + 1 < textLength) { if (i + 1 < textLength) {
if (text[i + 1] == '\n') { if (text.GetCharAt(i + 1) == '\n') {
return new SimpleSegment(i, 2); return new SimpleSegment(i, 2);
} }
} }
@ -61,6 +58,39 @@ namespace ICSharpCode.AvalonEdit.Document
} }
return SimpleSegment.Invalid; return SimpleSegment.Invalid;
} }
}
partial class TextUtilities
{
/// <summary>
/// Finds the next new line character starting at offset.
/// </summary>
/// <param name="text">The text source to search in.</param>
/// <param name="offset">The starting offset for the search.</param>
/// <param name="newLineType">The string representing the new line that was found, or null if no new line was found.</param>
/// <returns>The position of the first new line starting at or after <paramref name="offset"/>,
/// or -1 if no new line was found.</returns>
public static int FindNextNewLine(ITextSource text, int offset, out string newLineType)
{
if (text == null)
throw new ArgumentNullException("text");
if (offset < 0 || offset > text.TextLength)
throw new ArgumentOutOfRangeException("offset", offset, "offset is outside of text source");
SimpleSegment s = NewLineFinder.NextNewLine(text, offset);
if (s == SimpleSegment.Invalid) {
newLineType = null;
return -1;
} else {
if (s.Length == 2) {
newLineType = "\r\n";
} else if (text.GetCharAt(s.Offset) == '\n') {
newLineType = "\n";
} else {
newLineType = "\r";
}
return s.Offset;
}
}
/// <summary> /// <summary>
/// Gets whether the specified string is a newline sequence. /// Gets whether the specified string is a newline sequence.
@ -77,8 +107,9 @@ namespace ICSharpCode.AvalonEdit.Document
{ {
if (input == null) if (input == null)
return null; return null;
Debug.Assert(IsNewLine(newLine)); if (!IsNewLine(newLine))
SimpleSegment ds = NextNewLine(input, 0); throw new ArgumentException("newLine must be one of the known newline sequences");
SimpleSegment ds = NewLineFinder.NextNewLine(input, 0);
if (ds == SimpleSegment.Invalid) // text does not contain any new lines if (ds == SimpleSegment.Invalid) // text does not contain any new lines
return input; return input;
StringBuilder b = new StringBuilder(input.Length); StringBuilder b = new StringBuilder(input.Length);
@ -87,7 +118,7 @@ namespace ICSharpCode.AvalonEdit.Document
b.Append(input, lastEndOffset, ds.Offset - lastEndOffset); b.Append(input, lastEndOffset, ds.Offset - lastEndOffset);
b.Append(newLine); b.Append(newLine);
lastEndOffset = ds.EndOffset; lastEndOffset = ds.EndOffset;
ds = NextNewLine(input, lastEndOffset); ds = NewLineFinder.NextNewLine(input, lastEndOffset);
} while (ds != SimpleSegment.Invalid); } while (ds != SimpleSegment.Invalid);
// remaining string (after last newline) // remaining string (after last newline)
b.Append(input, lastEndOffset, input.Length - lastEndOffset); b.Append(input, lastEndOffset, input.Length - lastEndOffset);

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs

@ -95,7 +95,7 @@ namespace ICSharpCode.AvalonEdit.Document
throw new ArgumentNullException("initialText"); throw new ArgumentNullException("initialText");
rope = new Rope<char>(initialText); rope = new Rope<char>(initialText);
lineTree = new DocumentLineTree(this); lineTree = new DocumentLineTree(this);
lineManager = new LineManager(rope, lineTree, this); lineManager = new LineManager(lineTree, this);
lineTrackers.CollectionChanged += delegate { lineTrackers.CollectionChanged += delegate {
lineManager.UpdateListOfLineTrackers(); lineManager.UpdateListOfLineTrackers();
}; };
@ -138,7 +138,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <inheritdoc/> /// <inheritdoc/>
public char GetCharAt(int offset) public char GetCharAt(int offset)
{ {
VerifyAccess(); DebugVerifyAccess(); // frequently called, so must be fast in release builds
return rope[offset]; return rope[offset];
} }

22
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary> /// <summary>
/// Static helper methods for working with text. /// Static helper methods for working with text.
/// </summary> /// </summary>
public static class TextUtilities public static partial class TextUtilities
{ {
#region GetControlCharacterName #region GetControlCharacterName
// the names of the first 32 ASCII characters = Unicode C0 block // the names of the first 32 ASCII characters = Unicode C0 block
@ -122,15 +122,6 @@ namespace ICSharpCode.AvalonEdit.Document
return new SimpleSegment(pos, offset - pos); return new SimpleSegment(pos, offset - pos);
} }
/// <summary>
/// Gets the leading whitespace segment on the document line.
/// </summary>
[ObsoleteAttribute("Supporting this method causes DocumentLine to use more memory than otherwise necessary. It will be removed in a future AvalonEdit version.")]
public static ISegment GetLeadingWhitespace(DocumentLine documentLine)
{
return GetLeadingWhitespace(documentLine.Document, documentLine);
}
/// <summary> /// <summary>
/// Gets the leading whitespace segment on the document line. /// Gets the leading whitespace segment on the document line.
/// </summary> /// </summary>
@ -145,17 +136,6 @@ namespace ICSharpCode.AvalonEdit.Document
return GetWhitespaceAfter(document, documentLine.Offset); return GetWhitespaceAfter(document, documentLine.Offset);
} }
/// <summary>
/// Gets the trailing whitespace segment on the document line.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Whitespace",
Justification = "WPF uses 'Whitespace'")]
[ObsoleteAttribute("Supporting this method causes DocumentLine to use more memory than otherwise necessary. It will be removed in a future AvalonEdit version.")]
public static ISegment GetTrailingWhitespace(DocumentLine documentLine)
{
return GetTrailingWhitespace(documentLine.Document, documentLine);
}
/// <summary> /// <summary>
/// Gets the trailing whitespace segment on the document line. /// Gets the trailing whitespace segment on the document line.
/// </summary> /// </summary>

8
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs

@ -318,7 +318,7 @@ namespace ICSharpCode.AvalonEdit.Editing
} }
string text = textArea.Selection.GetText(textArea.Document); string text = textArea.Selection.GetText(textArea.Document);
text = NewLineFinder.NormalizeNewLines(text, Environment.NewLine); text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
textArea.OnTextCopied(new TextEventArgs(text)); textArea.OnTextCopied(new TextEventArgs(text));
} }
@ -329,7 +329,7 @@ namespace ICSharpCode.AvalonEdit.Editing
ISegment wholeLine = new SimpleSegment(line.Offset, line.TotalLength); ISegment wholeLine = new SimpleSegment(line.Offset, line.TotalLength);
string text = textArea.Document.GetText(wholeLine); string text = textArea.Document.GetText(wholeLine);
// Ensure we use the appropriate newline sequence for the OS // Ensure we use the appropriate newline sequence for the OS
text = NewLineFinder.NormalizeNewLines(text, Environment.NewLine); text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
DataObject data = new DataObject(text); DataObject data = new DataObject(text);
// Also copy text in HTML format to clipboard - good for pasting text into Word // Also copy text in HTML format to clipboard - good for pasting text into Word
@ -368,8 +368,8 @@ namespace ICSharpCode.AvalonEdit.Editing
Debug.WriteLine( Clipboard.GetText(TextDataFormat.Html) ); Debug.WriteLine( Clipboard.GetText(TextDataFormat.Html) );
// convert text back to correct newlines for this document // convert text back to correct newlines for this document
string newLine = NewLineFinder.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line); string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
string text = NewLineFinder.NormalizeNewLines(Clipboard.GetText(), newLine); string text = TextUtilities.NormalizeNewLines(Clipboard.GetText(), newLine);
if (!string.IsNullOrEmpty(text)) { if (!string.IsNullOrEmpty(text)) {
bool fullLine = textArea.Options.CutCopyWholeLine && Clipboard.ContainsData(LineSelectedType); bool fullLine = textArea.Options.CutCopyWholeLine && Clipboard.ContainsData(LineSelectedType);

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs

@ -172,7 +172,7 @@ namespace ICSharpCode.AvalonEdit.Editing
{ {
string text = GetText(textArea.Document); string text = GetText(textArea.Document);
// Ensure we use the appropriate newline sequence for the OS // Ensure we use the appropriate newline sequence for the OS
DataObject data = new DataObject(NewLineFinder.NormalizeNewLines(text, Environment.NewLine)); DataObject data = new DataObject(TextUtilities.NormalizeNewLines(text, Environment.NewLine));
// we cannot use DataObject.SetText - then we cannot drag to SciTe // we cannot use DataObject.SetText - then we cannot drag to SciTe
// (but dragging to Word works in both cases) // (but dragging to Word works in both cases)

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs

@ -192,8 +192,8 @@ namespace ICSharpCode.AvalonEdit.Editing
bool rectangular = e.Data.GetDataPresent(RectangleSelection.RectangularSelectionDataType); bool rectangular = e.Data.GetDataPresent(RectangleSelection.RectangularSelectionDataType);
string newLine = NewLineFinder.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line); string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
text = NewLineFinder.NormalizeNewLines(text, newLine); text = TextUtilities.NormalizeNewLines(text, newLine);
// Mark the undo group with the currentDragDescriptor, if the drag // Mark the undo group with the currentDragDescriptor, if the drag
// is originating from the same control. This allows combining // is originating from the same control. This allows combining

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs

@ -824,7 +824,7 @@ namespace ICSharpCode.AvalonEdit.Editing
void ReplaceSelectionWithNewLine() void ReplaceSelectionWithNewLine()
{ {
string newLine = NewLineFinder.GetNewLineFromDocument(this.Document, this.Caret.Line); string newLine = TextUtilities.GetNewLineFromDocument(this.Document, this.Caret.Line);
using (this.Document.RunUpdate()) { using (this.Document.RunUpdate()) {
ReplaceSelectionWithText(newLine); ReplaceSelectionWithText(newLine);
if (this.IndentationStrategy != null) { if (this.IndentationStrategy != null) {

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Snippets/InsertionContext.cs

@ -50,7 +50,7 @@ namespace ICSharpCode.AvalonEdit.Snippets
this.Indentation = Document.GetText(indentation.Offset, Math.Min(indentation.EndOffset, insertionPosition) - indentation.Offset); this.Indentation = Document.GetText(indentation.Offset, Math.Min(indentation.EndOffset, insertionPosition) - indentation.Offset);
this.Tab = textArea.Options.IndentationString; this.Tab = textArea.Options.IndentationString;
this.LineTerminator = NewLineFinder.GetNewLineFromDocument(this.Document, startLine.LineNumber); this.LineTerminator = TextUtilities.GetNewLineFromDocument(this.Document, startLine.LineNumber);
} }
/// <summary> /// <summary>

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs

@ -339,6 +339,8 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
public void RunLookupTableVisitor(INode currentMemberNode) public void RunLookupTableVisitor(INode currentMemberNode)
{ {
if (currentMemberNode == null)
throw new ArgumentNullException("currentMemberNode");
lookupTableVisitor = new LookupTableVisitor(language); lookupTableVisitor = new LookupTableVisitor(language);
currentMemberNode.AcceptVisitor(lookupTableVisitor, null); currentMemberNode.AcceptVisitor(lookupTableVisitor, null);
} }

Loading…
Cancel
Save