Browse Source

CodeEditor is now calling IFormattingStrategy.FormatLine.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4138 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts^2
Daniel Grunwald 16 years ago
parent
commit
ce435d7a0c
  1. 83
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs
  2. 45
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
  3. 14
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/EditingCommandHandler.cs
  4. 54
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Gui/TextArea.cs
  5. 4
      src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditDocumentAdapter.cs
  6. 6
      src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs
  7. 16
      src/Main/Base/Project/Src/Editor/DocumentUtilitites.cs
  8. 2
      src/Main/Base/Project/Src/Editor/IFormattingStrategy.cs
  9. 5
      src/Main/Base/Project/Src/Editor/ITextEditor.cs
  10. 4
      src/Main/Base/Project/Src/Services/RefactoringService/TextEditorDocument.cs
  11. 6
      src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs
  12. 6
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/IDocument.cs

83
src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs

@ -53,7 +53,6 @@ namespace CSharpBinding.FormattingStrategy @@ -53,7 +53,6 @@ namespace CSharpBinding.FormattingStrategy
}
#endregion
/*
#region Private functions
bool NeedCurlyBracket(string text)
{
@ -130,7 +129,7 @@ namespace CSharpBinding.FormattingStrategy @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 + " <summary>".Length + terminator.Length);
textArea.Caret.Offset = cursorOffset + indentation.Length + "/// ".Length + " <summary>".Length + terminator.Length;
}
}
return;
@ -321,7 +320,7 @@ namespace CSharpBinding.FormattingStrategy @@ -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 @@ -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 @@ -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 @@ -549,6 +543,7 @@ namespace CSharpBinding.FormattingStrategy
}
#endregion
/*
#region SearchBracketBackward
public override int SearchBracketBackward(IDocument document, int offset, char openBracket, char closingBracket)
{

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

@ -146,7 +146,8 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -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 @@ -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 @@ -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 @@ -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 @@ -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);

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

@ -73,17 +73,9 @@ namespace ICSharpCode.AvalonEdit.Gui @@ -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

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

@ -597,8 +597,25 @@ namespace ICSharpCode.AvalonEdit @@ -597,8 +597,25 @@ namespace ICSharpCode.AvalonEdit
/// This is like the <see cref="UIElement.TextInput"/> event,
/// but occurs immediately before the TextArea handles the TextInput event.
/// </summary>
public event TextCompositionEventHandler TextEntering;
/// <summary>
/// Occurs when the TextArea receives text input.
/// This is like the <see cref="UIElement.TextInput"/> event,
/// but occurs immediately after the TextArea handles the TextInput event.
/// </summary>
public event TextCompositionEventHandler TextEntered;
/// <summary>
/// Raises the TextEntering event.
/// </summary>
protected virtual void OnTextEntering(TextCompositionEventArgs e)
{
if (TextEntering != null) {
TextEntering(this, e);
}
}
/// <summary>
/// Raises the TextEntered event.
/// </summary>
@ -613,22 +630,49 @@ namespace ICSharpCode.AvalonEdit @@ -613,22 +630,49 @@ 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);
PerformTextInput(e);
e.Handled = true;
}
}
/// <summary>
/// Runs text input.
/// This raises the <see cref="TextEntering"/> event, replaces the selection with the text,
/// and then raises the <see cref="TextEntered"/> event.
/// </summary>
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();
e.Handled = true;
}
}
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);
}
}
}

4
src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditDocumentAdapter.cs

@ -55,6 +55,10 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -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; }
}

6
src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs

@ -113,6 +113,12 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -113,6 +113,12 @@ namespace ICSharpCode.SharpDevelop.Editor
return avalonEditOptions.IndentationString;
}
}
public bool AutoInsertBlockEnd {
get {
return true;
}
}
}
public virtual string FileName {

16
src/Main/Base/Project/Src/Editor/DocumentUtilitites.cs

@ -109,6 +109,22 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -109,6 +109,22 @@ namespace ICSharpCode.SharpDevelop.Editor
return document.GetText(segment.Offset, segment.Length);
}
/// <summary>
/// Gets the line terminator for the document around the specified line number.
/// </summary>
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)
{

2
src/Main/Base/Project/Src/Editor/IFormattingStrategy.cs

@ -10,7 +10,7 @@ using System; @@ -10,7 +10,7 @@ using System;
namespace ICSharpCode.SharpDevelop.Editor
{
/// <summary>
/// Indentation strategy.
/// Indentation and formatting strategy.
/// </summary>
public interface IFormattingStrategy
{

5
src/Main/Base/Project/Src/Editor/ITextEditor.cs

@ -88,6 +88,11 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -88,6 +88,11 @@ namespace ICSharpCode.SharpDevelop.Editor
/// Gets the text used for one indentation level.
/// </summary>
string IndentationString { get; }
/// <summary>
/// Gets whether a '}' should automatically be inserted when a block is opened.
/// </summary>
bool AutoInsertBlockEnd { get; }
}
public interface ITextEditorCaret

4
src/Main/Base/Project/Src/Services/RefactoringService/TextEditorDocument.cs

@ -54,6 +54,10 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -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; }
}

6
src/Main/Base/Project/Src/TextEditor/Gui/TextEditorAdapter.cs

@ -90,6 +90,12 @@ namespace ICSharpCode.SharpDevelop @@ -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)

6
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/IDocument.cs

@ -119,6 +119,12 @@ namespace ICSharpCode.SharpDevelop.Editor @@ -119,6 +119,12 @@ namespace ICSharpCode.SharpDevelop.Editor
/// </summary>
int TotalLength { get; }
/// <summary>
/// Gets the length of the line terminator.
/// Returns 1 or 2; or 0 at the end of the document.
/// </summary>
int DelimiterLength { get; }
/// <summary>
/// Gets the number of this line.
/// The first line has the number 1.

Loading…
Cancel
Save