diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs
index 16f8afe554..ee60a00e71 100644
--- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs
@@ -53,7 +53,6 @@ namespace CSharpBinding.FormattingStrategy
}
#endregion
- /*
#region Private functions
bool NeedCurlyBracket(string text)
{
@@ -130,7 +129,7 @@ namespace CSharpBinding.FormattingStrategy
}
- bool IsInsideStringOrComment(TextArea textArea, LineSegment curLine, int cursorOffset)
+ bool IsInsideStringOrComment(ITextEditor textArea, IDocumentLine curLine, int cursorOffset)
{
// scan cur line if it is inside a string or single line comment (//)
bool insideString = false;
@@ -164,7 +163,7 @@ namespace CSharpBinding.FormattingStrategy
return insideString;
}
- bool IsInsideDocumentationComment(TextArea textArea, LineSegment curLine, int cursorOffset)
+ bool IsInsideDocumentationComment(ITextEditor textArea, IDocumentLine curLine, int cursorOffset)
{
for (int i = curLine.Offset; i < cursorOffset; ++i) {
char ch = textArea.Document.GetCharAt(i);
@@ -246,8 +245,8 @@ namespace CSharpBinding.FormattingStrategy
{
int regions = 0;
int endregions = 0;
- foreach (LineSegment line in document.LineSegmentCollection) {
- string text = document.GetText(line).Trim();
+ for (int i = 1; i <= document.TotalNumberOfLines; i++) {
+ string text = document.GetLine(i).Text.Trim();
if (text.StartsWith("#region")) {
++regions;
} else if (text.StartsWith("#endregion")) {
@@ -256,26 +255,27 @@ namespace CSharpBinding.FormattingStrategy
}
return regions > endregions;
}
- public override void FormatLine(TextArea textArea, int lineNr, int cursorOffset, char ch) // used for comment tag formater/inserter
+
+ public override void FormatLine(ITextEditor textArea, char ch) // used for comment tag formater/inserter
{
- textArea.Document.UndoStack.StartUndoGroup();
- FormatLineInternal(textArea, lineNr, cursorOffset, ch);
- textArea.Document.UndoStack.EndUndoGroup();
+ using (textArea.Document.OpenUndoGroup()) {
+ FormatLineInternal(textArea, textArea.Caret.Line, textArea.Caret.Offset, ch);
+ }
}
- void FormatLineInternal(TextArea textArea, int lineNr, int cursorOffset, char ch)
+ void FormatLineInternal(ITextEditor textArea, int lineNr, int cursorOffset, char ch)
{
- LineSegment curLine = textArea.Document.GetLineSegment(lineNr);
- LineSegment lineAbove = lineNr > 0 ? textArea.Document.GetLineSegment(lineNr - 1) : null;
- string terminator = textArea.TextEditorProperties.LineTerminator;
+ IDocumentLine curLine = textArea.Document.GetLine(lineNr);
+ IDocumentLine lineAbove = lineNr > 1 ? textArea.Document.GetLine(lineNr - 1) : null;
+ string terminator = DocumentUtilitites.GetLineTerminator(textArea.Document, lineNr);
+ string curLineText;
//// local string for curLine segment
- string curLineText="";
if (ch == '/') {
- curLineText = textArea.Document.GetText(curLine);
- string lineAboveText = lineAbove == null ? "" : textArea.Document.GetText(lineAbove);
+ curLineText = curLine.Text;
+ string lineAboveText = lineAbove == null ? "" : lineAbove.Text;
if (curLineText != null && curLineText.EndsWith("///") && (lineAboveText == null || !lineAboveText.Trim().StartsWith("///"))) {
- string indentation = base.GetIndentation(textArea, lineNr);
+ string indentation = DocumentUtilitites.GetIndentation(textArea.Document, curLine.Offset);
object member = GetMemberAfter(textArea, lineNr);
if (member != null) {
StringBuilder sb = new StringBuilder();
@@ -306,8 +306,7 @@ namespace CSharpBinding.FormattingStrategy
}
textArea.Document.Insert(cursorOffset, sb.ToString());
- textArea.Refresh();
- textArea.Caret.Position = textArea.Document.OffsetToPosition(cursorOffset + indentation.Length + "/// ".Length + " ".Length + terminator.Length);
+ textArea.Caret.Offset = cursorOffset + indentation.Length + "/// ".Length + " ".Length + terminator.Length;
}
}
return;
@@ -321,7 +320,7 @@ namespace CSharpBinding.FormattingStrategy
switch (ch) {
case '>':
if (IsInsideDocumentationComment(textArea, curLine, cursorOffset)) {
- curLineText = textArea.Document.GetText(curLine);
+ curLineText = curLine.Text;
int column = textArea.Caret.Offset - curLine.Offset;
int index = Math.Min(column - 1, curLineText.Length - 1);
@@ -351,29 +350,24 @@ namespace CSharpBinding.FormattingStrategy
case ']':
case '}':
case '{':
- if (textArea.Document.TextEditorProperties.IndentStyle == IndentStyle.Smart) {
- textArea.Document.FormattingStrategy.IndentLine(textArea, lineNr);
- }
+ //if (textArea.Document.TextEditorProperties.IndentStyle == IndentStyle.Smart) {
+ IndentLine(textArea, curLine);
+ //}
break;
case '\n':
- string lineAboveText = lineAbove == null ? "" : textArea.Document.GetText(lineAbove);
+ string lineAboveText = lineAbove == null ? "" : lineAbove.Text;
//// curLine might have some text which should be added to indentation
- curLineText = "";
- if (curLine.Length > 0) {
- curLineText = textArea.Document.GetText(curLine);
- }
-
- LineSegment nextLine = lineNr + 1 < textArea.Document.TotalNumberOfLines ? textArea.Document.GetLineSegment(lineNr + 1) : null;
- string nextLineText = lineNr + 1 < textArea.Document.TotalNumberOfLines ? textArea.Document.GetText(nextLine) : "";
+ curLineText = curLine.Text;
- int addCursorOffset = 0;
-
- if (lineAboveText.Trim().StartsWith("#region") && NeedEndregion(textArea.Document)) {
- textArea.Document.Insert(curLine.Offset, "#endregion");
- textArea.Caret.Column = IndentLine(textArea, lineNr);
+ if (lineAbove != null && lineAbove.Text.Trim().StartsWith("#region")
+ && NeedEndregion(textArea.Document))
+ {
+ textArea.Document.Insert(cursorOffset, "#endregion");
return;
}
+ /*
+ int addCursorOffset = 0;
if (lineAbove.HighlightSpanStack != null && !lineAbove.HighlightSpanStack.IsEmpty) {
if (!lineAbove.HighlightSpanStack.Peek().StopEOL) { // case for /* style comments
int index = lineAboveText.IndexOf("/*");
@@ -421,18 +415,18 @@ namespace CSharpBinding.FormattingStrategy
addCursorOffset = 1;
}
}
- }
- int result = IndentLine(textArea, lineNr) + addCursorOffset;
- if (textArea.TextEditorProperties.AutoInsertCurlyBracket) {
- string oldLineText = TextUtilities.GetLineAsString(textArea.Document, lineNr - 1);
+ }*/
+ if (textArea.Options.AutoInsertBlockEnd && lineAbove != null) {
+ string oldLineText = lineAbove.Text;
if (oldLineText.EndsWith("{")) {
- if (NeedCurlyBracket(textArea.Document.TextContent)) {
- textArea.Document.Insert(curLine.Offset + curLine.Length, terminator + "}");
- IndentLine(textArea, lineNr + 1);
+ if (NeedCurlyBracket(textArea.Document.Text)) {
+ int insertionPoint = curLine.Offset + curLine.Length;
+ textArea.Document.Insert(insertionPoint, terminator + "}");
+ IndentLine(textArea, textArea.Document.GetLine(lineNr + 1));
+ textArea.Caret.Offset = insertionPoint;
}
}
}
- textArea.Caret.Column = result;
return;
}
}
@@ -549,6 +543,7 @@ namespace CSharpBinding.FormattingStrategy
}
#endregion
+ /*
#region SearchBracketBackward
public override int SearchBracketBackward(IDocument document, int offset, char openBracket, char closingBracket)
{
diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
index 3ea22bcd88..d64657bcc1 100644
--- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
+++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
@@ -146,7 +146,8 @@ namespace ICSharpCode.AvalonEdit.AddIn
textEditor.Background = Brushes.White;
textEditor.FontFamily = new FontFamily("Consolas");
textEditor.FontSize = 13;
- textEditor.TextArea.TextEntered += TextArea_TextInput;
+ textEditor.TextArea.TextEntering += TextArea_TextEntering;
+ textEditor.TextArea.TextEntered += TextArea_TextEntered;
textEditor.MouseHover += textEditor_MouseHover;
textEditor.MouseHoverStopped += textEditor_MouseHoverStopped;
textEditor.TextArea.Caret.PositionChanged += caret_PositionChanged;
@@ -171,15 +172,13 @@ namespace ICSharpCode.AvalonEdit.AddIn
void textEditor_TextArea_TextView_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
- ITextEditorComponent component = (ITextEditorComponent)sender;
- ITextEditor adapter = (ITextEditor)component.GetService(typeof(ITextEditor));
+ ITextEditor adapter = GetAdapterFromSender(sender);
MenuService.CreateContextMenu(adapter, contextMenuPath).IsOpen = true;
}
void textEditor_TextArea_TextView_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
- ITextEditorComponent component = (ITextEditorComponent)sender;
- TextEditor textEditor = (TextEditor)component.GetService(typeof(TextEditor));
+ TextEditor textEditor = GetTextEditorFromSender(sender);
var position = textEditor.GetPositionFromPoint(e.GetPosition(textEditor));
if (position.HasValue) {
textEditor.TextArea.Caret.Position = position.Value;
@@ -305,15 +304,16 @@ namespace ICSharpCode.AvalonEdit.AddIn
}
}
- void TextArea_TextInput(object sender, TextCompositionEventArgs e)
+ void TextArea_TextEntering(object sender, TextCompositionEventArgs e)
{
// don't start new code completion if there is still a completion window open
if (completionWindow != null)
return;
- TextArea textArea = (TextArea)sender;
- ITextEditor adapter = (ITextEditor)textArea.GetService(typeof(ITextEditor));
- Debug.Assert(adapter != null);
+ if (e.Handled)
+ return;
+
+ ITextEditor adapter = GetAdapterFromSender(sender);
foreach (char c in e.Text) {
foreach (ICodeCompletionBinding cc in CodeCompletionBindings) {
@@ -343,18 +343,35 @@ namespace ICSharpCode.AvalonEdit.AddIn
}
}
- TextEditor GetTextEditorFromRoutedCommand(object sender)
+ void TextArea_TextEntered(object sender, TextCompositionEventArgs e)
+ {
+ if (e.Text.Length > 0 && !e.Handled) {
+ formattingStrategy.FormatLine(GetAdapterFromSender(sender), e.Text[0]);
+ }
+ }
+
+ ITextEditor GetAdapterFromSender(object sender)
+ {
+ ITextEditorComponent textArea = (ITextEditorComponent)sender;
+ ITextEditor textEditor = (ITextEditor)textArea.GetService(typeof(ITextEditor));
+ if (textEditor == null)
+ throw new InvalidOperationException("could not find TextEditor service");
+ return textEditor;
+ }
+
+ TextEditor GetTextEditorFromSender(object sender)
{
- TextArea textArea = (TextArea)sender;
+ ITextEditorComponent textArea = (ITextEditorComponent)sender;
TextEditor textEditor = (TextEditor)textArea.GetService(typeof(TextEditor));
- Debug.Assert(textEditor != null);
+ if (textEditor == null)
+ throw new InvalidOperationException("could not find TextEditor service");
return textEditor;
}
void OnCodeCompletion(object sender, ExecutedRoutedEventArgs e)
{
CloseExistingCompletionWindows();
- TextEditor textEditor = GetTextEditorFromRoutedCommand(sender);
+ TextEditor textEditor = GetTextEditorFromSender(sender);
foreach (ICodeCompletionBinding cc in CodeCompletionBindings) {
if (cc.CtrlSpace(GetAdapter(textEditor))) {
e.Handled = true;
@@ -365,7 +382,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
void OnDeleteLine(object sender, ExecutedRoutedEventArgs e)
{
- TextEditor textEditor = GetTextEditorFromRoutedCommand(sender);
+ TextEditor textEditor = GetTextEditorFromSender(sender);
e.Handled = true;
using (textEditor.Document.RunUpdate()) {
DocumentLine currentLine = textEditor.Document.GetLineByNumber(textEditor.TextArea.Caret.Line);
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs
index 915eec2f88..0a306d6398 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs
@@ -73,17 +73,9 @@ namespace ICSharpCode.AvalonEdit.Gui
static void OnEnter(object target, ExecutedRoutedEventArgs args)
{
TextArea textArea = GetTextArea(target);
- if (textArea != null && textArea.Document != null) {
- string newLine = NewLineFinder.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
- using (textArea.Document.RunUpdate()) {
- textArea.ReplaceSelectionWithText(newLine);
- if (textArea.IndentationStrategy != null) {
- DocumentLine line = textArea.Document.GetLineByNumber(textArea.Caret.Line);
- textArea.IndentationStrategy.IndentLine(line);
- }
- }
- textArea.Caret.BringCaretToView();
- args.Handled = true;
+ if (textArea != null) {
+ TextComposition textComposition = new TextComposition(InputManager.Current, textArea, "\n");
+ textArea.PerformTextInput(new TextCompositionEventArgs(Keyboard.PrimaryDevice, textComposition));
}
}
#endregion
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs
index c46fc10e04..cff3e201b8 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs
@@ -597,8 +597,25 @@ namespace ICSharpCode.AvalonEdit
/// This is like the event,
/// but occurs immediately before the TextArea handles the TextInput event.
///
+ public event TextCompositionEventHandler TextEntering;
+
+ ///
+ /// Occurs when the TextArea receives text input.
+ /// This is like the event,
+ /// but occurs immediately after the TextArea handles the TextInput event.
+ ///
public event TextCompositionEventHandler TextEntered;
+ ///
+ /// Raises the TextEntering event.
+ ///
+ protected virtual void OnTextEntering(TextCompositionEventArgs e)
+ {
+ if (TextEntering != null) {
+ TextEntering(this, e);
+ }
+ }
+
///
/// Raises the TextEntered event.
///
@@ -613,21 +630,48 @@ namespace ICSharpCode.AvalonEdit
protected override void OnTextInput(TextCompositionEventArgs e)
{
base.OnTextInput(e);
- if (!e.Handled) {
+ if (!e.Handled && this.Document != null) {
if (e.Text == "\x1b") {
// ASCII 0x1b = ESC.
// WPF produces a TextInput event with that old ASCII control char
// when Escape is pressed. We'll just ignore it.
return;
}
- TextDocument document = this.Document;
- if (document != null) {
- OnTextEntered(e);
- if (!e.Handled) {
- ReplaceSelectionWithText(e.Text);
- caret.BringCaretToView();
- e.Handled = true;
- }
+ PerformTextInput(e);
+ e.Handled = true;
+ }
+ }
+
+ ///
+ /// Runs text input.
+ /// This raises the event, replaces the selection with the text,
+ /// and then raises the event.
+ ///
+ public void PerformTextInput(TextCompositionEventArgs e)
+ {
+ if (e == null)
+ throw new ArgumentNullException("e");
+ if (this.Document == null)
+ throw ThrowUtil.NoDocumentAssigned();
+ OnTextEntering(e);
+ if (!e.Handled) {
+ if (e.Text == "\n" || e.Text == "\r\n")
+ ReplaceSelectionWithNewLine();
+ else
+ ReplaceSelectionWithText(e.Text);
+ OnTextEntered(e);
+ caret.BringCaretToView();
+ }
+ }
+
+ void ReplaceSelectionWithNewLine()
+ {
+ string newLine = NewLineFinder.GetNewLineFromDocument(this.Document, this.Caret.Line);
+ using (this.Document.RunUpdate()) {
+ ReplaceSelectionWithText(newLine);
+ if (this.IndentationStrategy != null) {
+ DocumentLine line = this.Document.GetLineByNumber(this.Caret.Line);
+ this.IndentationStrategy.IndentLine(line);
}
}
}
diff --git a/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditDocumentAdapter.cs b/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditDocumentAdapter.cs
index 49424b947e..9fe935be2a 100644
--- a/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditDocumentAdapter.cs
+++ b/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditDocumentAdapter.cs
@@ -55,6 +55,10 @@ namespace ICSharpCode.SharpDevelop.Editor
get { return line.TotalLength; }
}
+ public int DelimiterLength {
+ get { return line.DelimiterLength; }
+ }
+
public int LineNumber {
get { return line.LineNumber; }
}
diff --git a/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs b/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs
index 3a79341b49..882950dc7f 100644
--- a/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs
+++ b/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs
@@ -113,6 +113,12 @@ namespace ICSharpCode.SharpDevelop.Editor
return avalonEditOptions.IndentationString;
}
}
+
+ public bool AutoInsertBlockEnd {
+ get {
+ return true;
+ }
+ }
}
public virtual string FileName {
diff --git a/src/Main/Base/Project/Src/Editor/DocumentUtilitites.cs b/src/Main/Base/Project/Src/Editor/DocumentUtilitites.cs
index 590efe75fa..4d2333dcb6 100644
--- a/src/Main/Base/Project/Src/Editor/DocumentUtilitites.cs
+++ b/src/Main/Base/Project/Src/Editor/DocumentUtilitites.cs
@@ -109,6 +109,22 @@ namespace ICSharpCode.SharpDevelop.Editor
return document.GetText(segment.Offset, segment.Length);
}
+ ///
+ /// Gets the line terminator for the document around the specified line number.
+ ///
+ public static string GetLineTerminator(IDocument document, int lineNumber)
+ {
+ IDocumentLine line = document.GetLine(lineNumber);
+ if (line.DelimiterLength == 0) {
+ // at the end of the document, there's no line delimiter, so use the delimiter
+ // from the previous line
+ if (lineNumber == 1)
+ return Environment.NewLine;
+ line = document.GetLine(lineNumber - 1);
+ }
+ return document.GetText(line.Offset + line.Length, line.DelimiterLength);
+ }
+
#region ITextSource implementation
public static ICSharpCode.AvalonEdit.Document.ITextSource GetTextSource(IDocument document)
{
diff --git a/src/Main/Base/Project/Src/Editor/IFormattingStrategy.cs b/src/Main/Base/Project/Src/Editor/IFormattingStrategy.cs
index 3552bcf075..0d11f448f3 100644
--- a/src/Main/Base/Project/Src/Editor/IFormattingStrategy.cs
+++ b/src/Main/Base/Project/Src/Editor/IFormattingStrategy.cs
@@ -10,7 +10,7 @@ using System;
namespace ICSharpCode.SharpDevelop.Editor
{
///
- /// Indentation strategy.
+ /// Indentation and formatting strategy.
///
public interface IFormattingStrategy
{
diff --git a/src/Main/Base/Project/Src/Editor/ITextEditor.cs b/src/Main/Base/Project/Src/Editor/ITextEditor.cs
index ccee44dd78..8d079db8fb 100644
--- a/src/Main/Base/Project/Src/Editor/ITextEditor.cs
+++ b/src/Main/Base/Project/Src/Editor/ITextEditor.cs
@@ -88,6 +88,11 @@ namespace ICSharpCode.SharpDevelop.Editor
/// Gets the text used for one indentation level.
///
string IndentationString { get; }
+
+ ///
+ /// Gets whether a '}' should automatically be inserted when a block is opened.
+ ///
+ bool AutoInsertBlockEnd { get; }
}
public interface ITextEditorCaret
diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/TextEditorDocument.cs b/src/Main/Base/Project/Src/Services/RefactoringService/TextEditorDocument.cs
index 5c4d5dff63..99abd62341 100644
--- a/src/Main/Base/Project/Src/Services/RefactoringService/TextEditorDocument.cs
+++ b/src/Main/Base/Project/Src/Services/RefactoringService/TextEditorDocument.cs
@@ -54,6 +54,10 @@ namespace ICSharpCode.SharpDevelop.Refactoring
get { return line.TotalLength; }
}
+ public int DelimiterLength {
+ get { return line.DelimiterLength; }
+ }
+
public int LineNumber {
get { return line.LineNumber + 1; }
}
diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs b/src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs
index a901937fe4..7044150653 100644
--- a/src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs
+++ b/src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs
@@ -90,6 +90,12 @@ namespace ICSharpCode.SharpDevelop
return properties.ConvertTabsToSpaces ? new string(' ', properties.IndentationSize) : "\t";
}
}
+
+ public bool AutoInsertBlockEnd {
+ get {
+ return true;
+ }
+ }
}
static ICSharpCode.NRefactory.Location ToLocation(TextLocation position)
diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/IDocument.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/IDocument.cs
index dc5ac923d7..0fc2adeea1 100644
--- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/IDocument.cs
+++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/IDocument.cs
@@ -119,6 +119,12 @@ namespace ICSharpCode.SharpDevelop.Editor
///
int TotalLength { get; }
+ ///
+ /// Gets the length of the line terminator.
+ /// Returns 1 or 2; or 0 at the end of the document.
+ ///
+ int DelimiterLength { get; }
+
///
/// Gets the number of this line.
/// The first line has the number 1.