Browse Source

Normalize newlines on copy/paste. Moved LineManager.NextDelimiter into NewLineFinder.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3838 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
65d02dc1e4
  1. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs
  2. 61
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/LineManager.cs
  3. 71
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs
  4. 12
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs
  5. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/WeakLineTracker.cs
  6. 1
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs
  7. 19
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs
  8. 4
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/HeightTree.cs
  9. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/LineNumberMargin.cs
  10. 1
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs
  11. 1
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs
  12. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs
  13. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/DocumentHighlighter.cs
  14. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -28,7 +28,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Represents a simple segment (Offset,Length pair) that is not automatically updated
/// on document changed.
/// on document changes.
/// </summary>
struct SimpleSegment : IEquatable<SimpleSegment>, ISegment
{

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

@ -26,14 +26,14 @@ namespace ICSharpCode.AvalonEdit.Document @@ -26,14 +26,14 @@ namespace ICSharpCode.AvalonEdit.Document
/// A copy of the line trackers. We need a copy so that line trackers may remove themselves
/// while being notified (used e.g. by WeakLineTracker)
/// </summary>
internal ILineTracker[] lineTracker;
internal ILineTracker[] lineTrackers;
public LineManager(GapTextBuffer textBuffer, DocumentLineTree documentLineTree, TextDocument document)
{
this.document = document;
this.textBuffer = textBuffer;
this.documentLineTree = documentLineTree;
this.lineTracker = document.LineTracker.ToArray();
this.lineTrackers = document.LineTrackers.ToArray();
}
#endregion
@ -87,24 +87,24 @@ namespace ICSharpCode.AvalonEdit.Document @@ -87,24 +87,24 @@ namespace ICSharpCode.AvalonEdit.Document
{
// keep the first document line
DocumentLine ls = documentLineTree.GetByNumber(1);
DelimiterSegment ds = NextDelimiter(text, 0);
SimpleSegment ds = NewLineFinder.NextNewLine(text, 0);
List<DocumentLine> lines = new List<DocumentLine>();
int lastDelimiterEnd = 0;
while (ds != null) {
while (ds != SimpleSegment.Invalid) {
ls.TotalLength = ds.Offset + ds.Length - lastDelimiterEnd;
ls.DelimiterLength = ds.Length;
lastDelimiterEnd = ds.Offset + ds.Length;
lines.Add(ls);
ls = new DocumentLine(document);
ds = NextDelimiter(text, lastDelimiterEnd);
ds = NewLineFinder.NextNewLine(text, lastDelimiterEnd);
}
ls.ResetLine();
ls.TotalLength = text.Length - lastDelimiterEnd;
lines.Add(ls);
documentLineTree.RebuildTree(lines);
foreach (ILineTracker lt in lineTracker)
lt.RebuildDocument();
foreach (ILineTracker lineTracker in lineTrackers)
lineTracker.RebuildDocument();
}
#endregion
@ -168,7 +168,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -168,7 +168,7 @@ namespace ICSharpCode.AvalonEdit.Document
void RemoveLine(DocumentLine lineToRemove)
{
foreach (ILineTracker lt in lineTracker)
foreach (ILineTracker lt in lineTrackers)
lt.BeforeRemoveLine(lineToRemove);
documentLineTree.RemoveLine(lineToRemove);
// foreach (ILineTracker lt in lineTracker)
@ -197,8 +197,8 @@ namespace ICSharpCode.AvalonEdit.Document @@ -197,8 +197,8 @@ namespace ICSharpCode.AvalonEdit.Document
line = SetLineLength(line, 1);
}
DelimiterSegment ds = NextDelimiter(text, 0);
if (ds == null) {
SimpleSegment ds = NewLineFinder.NextNewLine(text, 0);
if (ds == SimpleSegment.Invalid) {
// no newline is being inserted, all text is inserted in a single line
//line.InsertedLinePart(offset - line.Offset, text.Length);
SetLineLength(line, line.TotalLength + text.Length);
@ -207,7 +207,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -207,7 +207,7 @@ namespace ICSharpCode.AvalonEdit.Document
//DocumentLine firstLine = line;
//firstLine.InsertedLinePart(offset - firstLine.Offset, ds.Offset);
int lastDelimiterEnd = 0;
while (ds != null) {
while (ds != SimpleSegment.Invalid) {
// split line segment at line delimiter
int lineBreakOffset = offset + ds.Offset + ds.Length;
lineOffset = line.Offset;
@ -219,7 +219,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -219,7 +219,7 @@ namespace ICSharpCode.AvalonEdit.Document
line = newLine;
lastDelimiterEnd = ds.Offset + ds.Length;
ds = NextDelimiter(text, lastDelimiterEnd);
ds = NewLineFinder.NextNewLine(text, lastDelimiterEnd);
}
//firstLine.SplitTo(line);
// insert rest after last delimiter
@ -232,7 +232,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -232,7 +232,7 @@ namespace ICSharpCode.AvalonEdit.Document
DocumentLine InsertLineAfter(DocumentLine line, int length)
{
DocumentLine newLine = documentLineTree.InsertLineAfter(line, length);
foreach (ILineTracker lt in lineTracker)
foreach (ILineTracker lt in lineTrackers)
lt.LineInserted(line, newLine);
return newLine;
}
@ -252,7 +252,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -252,7 +252,7 @@ namespace ICSharpCode.AvalonEdit.Document
// deletedOrChangedLines.Add(line);
int delta = newTotalLength - line.TotalLength;
if (delta != 0) {
foreach (ILineTracker lt in lineTracker)
foreach (ILineTracker lt in lineTrackers)
lt.SetLineLength(line, newTotalLength);
line.TotalLength = newTotalLength;
DocumentLineTree.UpdateAfterChildrenChange(line);
@ -284,38 +284,5 @@ namespace ICSharpCode.AvalonEdit.Document @@ -284,38 +284,5 @@ namespace ICSharpCode.AvalonEdit.Document
return line;
}
#endregion
#region Delimiter
sealed class DelimiterSegment
{
internal int Offset;
internal int Length;
}
// always use the same DelimiterSegment object for the NextDelimiter
DelimiterSegment delimiterSegment = new DelimiterSegment();
DelimiterSegment NextDelimiter(string text, int offset)
{
for (int i = offset; i < text.Length; i++) {
switch (text[i]) {
case '\r':
if (i + 1 < text.Length) {
if (text[i + 1] == '\n') {
delimiterSegment.Offset = i;
delimiterSegment.Length = 2;
return delimiterSegment;
}
}
goto case '\n';
case '\n':
delimiterSegment.Offset = i;
delimiterSegment.Length = 1;
return delimiterSegment;
}
}
return null;
}
#endregion
}
}

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

@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
// <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.Diagnostics;
using System.Text;
namespace ICSharpCode.AvalonEdit.Document
{
/// <summary>
/// Helper methods for finding new lines.
/// </summary>
static class NewLineFinder
{
/// <summary>
/// Gets the location of the next new line character, or SimpleSegment.Invalid
/// if none is found.
/// </summary>
public static SimpleSegment NextNewLine(string text, int offset)
{
for (int i = offset; i < text.Length; i++) {
switch (text[i]) {
case '\r':
if (i + 1 < text.Length) {
if (text[i + 1] == '\n') {
return new SimpleSegment(i, 2);
}
}
goto case '\n';
case '\n':
return new SimpleSegment(i, 1);
}
}
return SimpleSegment.Invalid;
}
/// <summary>
/// Gets whether the specified string is a newline sequence.
/// </summary>
public static bool IsNewLine(string newLine)
{
return newLine == "\r\n" || newLine == "\n" || newLine == "\r";
}
/// <summary>
/// Normalizes all new lines in <paramref name="input"/> to be <paramref name="newLine"/>.
/// </summary>
public static string NormalizeNewLines(string input, string newLine)
{
Debug.Assert(IsNewLine(newLine));
SimpleSegment ds = NextNewLine(input, 0);
if (ds == SimpleSegment.Invalid) // text does not contain any new lines
return input;
StringBuilder b = new StringBuilder(input.Length);
int lastEndOffset = 0;
do {
b.Append(input, lastEndOffset, ds.Offset - lastEndOffset);
b.Append(newLine);
lastEndOffset = ds.GetEndOffset();
ds = NextNewLine(input, lastEndOffset);
} while (ds != SimpleSegment.Invalid);
// remaining string (after last newline)
b.Append(input, lastEndOffset, input.Length - lastEndOffset);
return b.ToString();
}
}
}

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

@ -74,8 +74,8 @@ namespace ICSharpCode.AvalonEdit.Document @@ -74,8 +74,8 @@ namespace ICSharpCode.AvalonEdit.Document
//parserManager = new ParserManager(this);
lineTree = new DocumentLineTree(this);
lineManager = new LineManager(textBuffer, lineTree, this);
lineTracker.CollectionChanged += delegate {
lineManager.lineTracker = lineTracker.ToArray();
lineTrackers.CollectionChanged += delegate {
lineManager.lineTrackers = lineTrackers.ToArray();
};
anchorTree = new TextAnchorTree(this);
@ -445,15 +445,15 @@ namespace ICSharpCode.AvalonEdit.Document @@ -445,15 +445,15 @@ namespace ICSharpCode.AvalonEdit.Document
return new TextLocation(line.LineNumber, offset - line.Offset + 1);
}
readonly ObservableCollection<ILineTracker> lineTracker = new ObservableCollection<ILineTracker>();
readonly ObservableCollection<ILineTracker> lineTrackers = new ObservableCollection<ILineTracker>();
/// <summary>
/// Gets the list of <see cref="ILineTracker"/> attached to this document.
/// Gets the list of <see cref="ILineTracker"/>s attached to this document.
/// </summary>
public IList<ILineTracker> LineTracker {
public IList<ILineTracker> LineTrackers {
get {
VerifyAccess();
return lineTracker;
return lineTrackers;
}
}

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/WeakLineTracker.cs

@ -22,7 +22,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -22,7 +22,7 @@ namespace ICSharpCode.AvalonEdit.Document
void Deregister()
{
textDocument.LineTracker.Remove(this);
textDocument.LineTrackers.Remove(this);
}
public void BeforeRemoveLine(DocumentLine line)

1
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/CaretNavigationCommandHandler.cs

@ -44,7 +44,6 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -44,7 +44,6 @@ namespace ICSharpCode.AvalonEdit.Gui
InputBindings.Add(new KeyBinding(command, key, modifiers));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
static CaretNavigationCommandHandler()
{
const ModifierKeys None = ModifierKeys.None;

19
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs

@ -7,7 +7,6 @@ @@ -7,7 +7,6 @@
using System;
using System.Linq;
using System.Diagnostics;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
@ -28,7 +27,6 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -28,7 +27,6 @@ namespace ICSharpCode.AvalonEdit.Gui
InputBindings.Add(new KeyBinding(command, key, modifiers));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
static EditingCommandHandler()
{
CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete, OnDelete(ApplicationCommands.NotACommand), HasSomethingSelected));
@ -198,7 +196,7 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -198,7 +196,7 @@ namespace ICSharpCode.AvalonEdit.Gui
{
TextArea textArea = GetTextArea(target);
if (textArea != null && textArea.Document != null) {
Clipboard.SetText(textArea.Selection.GetText(textArea.Document));
CopySelectedText(textArea);
args.Handled = true;
}
}
@ -207,13 +205,20 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -207,13 +205,20 @@ namespace ICSharpCode.AvalonEdit.Gui
{
TextArea textArea = GetTextArea(target);
if (textArea != null && textArea.Document != null) {
Clipboard.SetText(textArea.Selection.GetText(textArea.Document));
CopySelectedText(textArea);
textArea.RemoveSelectedText();
textArea.Caret.BringCaretToView();
args.Handled = true;
}
}
static void CopySelectedText(TextArea textArea)
{
string text = textArea.Selection.GetText(textArea.Document);
// ensure we use the appropriate newline sequence for the OS
Clipboard.SetText(NewLineFinder.NormalizeNewLines(text, Environment.NewLine));
}
static void CanPaste(object target, CanExecuteRoutedEventArgs args)
{
TextArea textArea = GetTextArea(target);
@ -228,8 +233,10 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -228,8 +233,10 @@ namespace ICSharpCode.AvalonEdit.Gui
{
TextArea textArea = GetTextArea(target);
if (textArea != null && textArea.Document != null) {
// TODO: normalize newlines on paste
textArea.ReplaceSelectionWithText(Clipboard.GetText());
// convert text back to correct newlines for this document
string newLine = GetLineDelimiter(textArea.Document, textArea.Caret.Line);
string text = NewLineFinder.NormalizeNewLines(Clipboard.GetText(), newLine);
textArea.ReplaceSelectionWithText(text);
textArea.Caret.BringCaretToView();
args.Handled = true;
}

4
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/HeightTree.cs

@ -51,7 +51,7 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -51,7 +51,7 @@ namespace ICSharpCode.AvalonEdit.Gui
{
this.document = document;
weakLineTracker = new WeakLineTracker(document, this);
document.LineTracker.Add(weakLineTracker);
document.LineTrackers.Add(weakLineTracker);
this.DefaultLineHeight = defaultLineHeight;
RebuildDocument();
}
@ -59,7 +59,7 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -59,7 +59,7 @@ namespace ICSharpCode.AvalonEdit.Gui
public void Dispose()
{
if (weakLineTracker != null)
document.LineTracker.Remove(weakLineTracker);
document.LineTrackers.Remove(weakLineTracker);
this.dict = null;
this.root = null;
this.weakLineTracker = null;

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/LineNumberMargin.cs

@ -23,7 +23,6 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -23,7 +23,6 @@ namespace ICSharpCode.AvalonEdit.Gui
/// </summary>
public class LineNumberMargin : AbstractMargin, IWeakEventListener
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
static LineNumberMargin()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(LineNumberMargin),
@ -226,7 +225,7 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -226,7 +225,7 @@ namespace ICSharpCode.AvalonEdit.Gui
/// <inheritdoc/>
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
// accept clicks even when clicking on the backgroudn
// accept clicks even when clicking on the background
return new PointHitTestResult(this, hitTestParameters.HitPoint);
}
}

1
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs

@ -30,7 +30,6 @@ namespace ICSharpCode.AvalonEdit @@ -30,7 +30,6 @@ namespace ICSharpCode.AvalonEdit
public class TextArea : Control, IScrollInfo, IWeakEventListener
{
#region Constructor
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
static TextArea()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TextArea),

1
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextEditor.cs

@ -29,7 +29,6 @@ namespace ICSharpCode.AvalonEdit @@ -29,7 +29,6 @@ namespace ICSharpCode.AvalonEdit
[Localizability(LocalizationCategory.Text), ContentProperty("Text")]
public class TextEditor : Control
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
static TextEditor()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TextEditor),

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextView.cs

@ -36,7 +36,6 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -36,7 +36,6 @@ namespace ICSharpCode.AvalonEdit.Gui
public class TextView : FrameworkElement, IScrollInfo, IWeakEventListener
{
#region Constructor
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
static TextView()
{
ClipToBoundsProperty.OverrideMetadata(typeof(TextView), new FrameworkPropertyMetadata(true));
@ -341,6 +340,7 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -341,6 +340,7 @@ namespace ICSharpCode.AvalonEdit.Gui
/// or use the <see cref="EnsureVisualLines()"/> method to force creating the visual lines
/// when they are invalid.
/// </exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
public ReadOnlyCollection<VisualLine> VisualLines {
get {
if (visibleVisualLines == null)

2
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/DocumentHighlighter.cs

@ -39,7 +39,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting @@ -39,7 +39,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting
throw new ArgumentNullException("baseRuleSet");
this.document = document;
this.baseRuleSet = baseRuleSet;
document.LineTracker.Add(new WeakLineTracker(document, this));
document.LineTrackers.Add(new WeakLineTracker(document, this));
InvalidateHighlighting();
}

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj

@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
<DelaySign>False</DelaySign>
<AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode>
<RunCodeAnalysis>False</RunCodeAnalysis>
<CodeAnalysisRules>-Microsoft.Design#CA1020;-Microsoft.Design#CA1033</CodeAnalysisRules>
<CodeAnalysisRules>-Microsoft.Design#CA1020;-Microsoft.Design#CA1033;-Microsoft.Performance#CA1810</CodeAnalysisRules>
<OutputPath>..\..\..\..\bin\</OutputPath>
<DocumentationFile>..\..\..\..\bin\ICSharpCode.AvalonEdit.xml</DocumentationFile>
</PropertyGroup>
@ -82,6 +82,7 @@ @@ -82,6 +82,7 @@
<Compile Include="Document\LineNode.cs">
<DependentUpon>DocumentLine.cs</DependentUpon>
</Compile>
<Compile Include="Document\NewLineFinder.cs" />
<Compile Include="Document\TextDocumentWeakEventManager.cs">
<DependentUpon>TextDocument.cs</DependentUpon>
</Compile>

Loading…
Cancel
Save