first commit
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Document
|
||||
{
|
||||
/// <summary>
|
||||
/// This class handles the auto and smart indenting in the textbuffer while
|
||||
/// you type.
|
||||
/// </summary>
|
||||
public class DefaultFormattingStrategy : IFormattingStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance off <see cref="DefaultFormattingStrategy"/>
|
||||
/// </summary>
|
||||
public DefaultFormattingStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// returns the whitespaces which are before a non white space character in the line line
|
||||
/// as a string.
|
||||
/// </summary>
|
||||
protected string GetIndentation(TextArea textArea, int lineNumber)
|
||||
{
|
||||
if (lineNumber < 0 || lineNumber > textArea.Document.TotalNumberOfLines) {
|
||||
throw new ArgumentOutOfRangeException("lineNumber");
|
||||
}
|
||||
|
||||
string lineText = TextUtilities.GetLineAsString(textArea.Document, lineNumber);
|
||||
StringBuilder whitespaces = new StringBuilder();
|
||||
|
||||
foreach (char ch in lineText) {
|
||||
if (char.IsWhiteSpace(ch)) {
|
||||
whitespaces.Append(ch);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return whitespaces.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Could be overwritten to define more complex indenting.
|
||||
/// </summary>
|
||||
protected virtual int AutoIndentLine(TextArea textArea, int lineNumber)
|
||||
{
|
||||
string indentation = lineNumber != 0 ? GetIndentation(textArea, lineNumber - 1) : "";
|
||||
if(indentation.Length > 0) {
|
||||
string newLineText = indentation + TextUtilities.GetLineAsString(textArea.Document, lineNumber).Trim();
|
||||
LineSegment oldLine = textArea.Document.GetLineSegment(lineNumber);
|
||||
SmartReplaceLine(textArea.Document, oldLine, newLineText);
|
||||
}
|
||||
return indentation.Length;
|
||||
}
|
||||
|
||||
static readonly char[] whitespaceChars = {' ', '\t'};
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the text in a line.
|
||||
/// If only whitespace at the beginning and end of the line was changed, this method
|
||||
/// only adjusts the whitespace and doesn't replace the other text.
|
||||
/// </summary>
|
||||
public static void SmartReplaceLine(IDocument document, LineSegment line, string newLineText)
|
||||
{
|
||||
if (document == null)
|
||||
throw new ArgumentNullException("document");
|
||||
if (line == null)
|
||||
throw new ArgumentNullException("line");
|
||||
if (newLineText == null)
|
||||
throw new ArgumentNullException("newLineText");
|
||||
string newLineTextTrim = newLineText.Trim(whitespaceChars);
|
||||
string oldLineText = document.GetText(line);
|
||||
if (oldLineText == newLineText)
|
||||
return;
|
||||
int pos = oldLineText.IndexOf(newLineTextTrim);
|
||||
if (newLineTextTrim.Length > 0 && pos >= 0) {
|
||||
document.UndoStack.StartUndoGroup();
|
||||
try {
|
||||
// find whitespace at beginning
|
||||
int startWhitespaceLength = 0;
|
||||
while (startWhitespaceLength < newLineText.Length) {
|
||||
char c = newLineText[startWhitespaceLength];
|
||||
if (c != ' ' && c != '\t')
|
||||
break;
|
||||
startWhitespaceLength++;
|
||||
}
|
||||
// find whitespace at end
|
||||
int endWhitespaceLength = newLineText.Length - newLineTextTrim.Length - startWhitespaceLength;
|
||||
|
||||
// replace whitespace sections
|
||||
int lineOffset = line.Offset;
|
||||
document.Replace(lineOffset + pos + newLineTextTrim.Length, line.Length - pos - newLineTextTrim.Length, newLineText.Substring(newLineText.Length - endWhitespaceLength));
|
||||
document.Replace(lineOffset, pos, newLineText.Substring(0, startWhitespaceLength));
|
||||
} finally {
|
||||
document.UndoStack.EndUndoGroup();
|
||||
}
|
||||
} else {
|
||||
document.Replace(line.Offset, line.Length, newLineText);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Could be overwritten to define more complex indenting.
|
||||
/// </summary>
|
||||
protected virtual int SmartIndentLine(TextArea textArea, int line)
|
||||
{
|
||||
return AutoIndentLine(textArea, line); // smart = autoindent in normal texts
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function formats a specific line after <code>ch</code> is pressed.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// the caret delta position the caret will be moved this number
|
||||
/// of bytes (e.g. the number of bytes inserted before the caret, or
|
||||
/// removed, if this number is negative)
|
||||
/// </returns>
|
||||
public virtual void FormatLine(TextArea textArea, int line, int cursorOffset, char ch)
|
||||
{
|
||||
if (ch == '\n') {
|
||||
textArea.Caret.Column = IndentLine(textArea, line);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function sets the indentation level in a specific line
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// the number of inserted characters.
|
||||
/// </returns>
|
||||
public int IndentLine(TextArea textArea, int line)
|
||||
{
|
||||
textArea.Document.UndoStack.StartUndoGroup();
|
||||
int result;
|
||||
switch (textArea.Document.TextEditorProperties.IndentStyle) {
|
||||
case IndentStyle.None:
|
||||
result = 0;
|
||||
break;
|
||||
case IndentStyle.Auto:
|
||||
result = AutoIndentLine(textArea, line);
|
||||
break;
|
||||
case IndentStyle.Smart:
|
||||
result = SmartIndentLine(textArea, line);
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Unsupported value for IndentStyle: " + textArea.Document.TextEditorProperties.IndentStyle);
|
||||
}
|
||||
textArea.Document.UndoStack.EndUndoGroup();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function sets the indentlevel in a range of lines.
|
||||
/// </summary>
|
||||
public virtual void IndentLines(TextArea textArea, int begin, int end)
|
||||
{
|
||||
textArea.Document.UndoStack.StartUndoGroup();
|
||||
for (int i = begin; i <= end; ++i) {
|
||||
IndentLine(textArea, i);
|
||||
}
|
||||
textArea.Document.UndoStack.EndUndoGroup();
|
||||
}
|
||||
|
||||
public virtual int SearchBracketBackward(IDocument document, int offset, char openBracket, char closingBracket)
|
||||
{
|
||||
int brackets = -1;
|
||||
// first try "quick find" - find the matching bracket if there is no string/comment in the way
|
||||
for (int i = offset; i >= 0; --i) {
|
||||
char ch = document.GetCharAt(i);
|
||||
if (ch == openBracket) {
|
||||
++brackets;
|
||||
if (brackets == 0) return i;
|
||||
} else if (ch == closingBracket) {
|
||||
--brackets;
|
||||
} else if (ch == '"') {
|
||||
break;
|
||||
} else if (ch == '\'') {
|
||||
break;
|
||||
} else if (ch == '/' && i > 0) {
|
||||
if (document.GetCharAt(i - 1) == '/') break;
|
||||
if (document.GetCharAt(i - 1) == '*') break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public virtual int SearchBracketForward(IDocument document, int offset, char openBracket, char closingBracket)
|
||||
{
|
||||
int brackets = 1;
|
||||
// try "quick find" - find the matching bracket if there is no string/comment in the way
|
||||
for (int i = offset; i < document.TextLength; ++i) {
|
||||
char ch = document.GetCharAt(i);
|
||||
if (ch == openBracket) {
|
||||
++brackets;
|
||||
} else if (ch == closingBracket) {
|
||||
--brackets;
|
||||
if (brackets == 0) return i;
|
||||
} else if (ch == '"') {
|
||||
break;
|
||||
} else if (ch == '\'') {
|
||||
break;
|
||||
} else if (ch == '/' && i > 0) {
|
||||
if (document.GetCharAt(i - 1) == '/') break;
|
||||
} else if (ch == '*' && i > 0) {
|
||||
if (document.GetCharAt(i - 1) == '/') break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System;
|
||||
|
||||
namespace ICSharpCode.TextEditor.Document
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface handles the auto and smart indenting and formating
|
||||
/// in the document while you type. Language bindings could overwrite this
|
||||
/// interface and define their own indentation/formating.
|
||||
/// </summary>
|
||||
public interface IFormattingStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// This function formats a specific line after <code>ch</code> is pressed.
|
||||
/// </summary>
|
||||
void FormatLine(TextArea textArea, int line, int caretOffset, char charTyped);
|
||||
|
||||
/// <summary>
|
||||
/// This function sets the indentation level in a specific line
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The target caret position (length of new indentation).
|
||||
/// </returns>
|
||||
int IndentLine(TextArea textArea, int line);
|
||||
|
||||
/// <summary>
|
||||
/// This function sets the indentlevel in a range of lines.
|
||||
/// </summary>
|
||||
void IndentLines(TextArea textArea, int begin, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the offset of the opening bracket in the block defined by offset skipping
|
||||
/// brackets in strings and comments.
|
||||
/// </summary>
|
||||
/// <param name="document">The document to search in.</param>
|
||||
/// <param name="offset">The offset of an position in the block or the offset of the closing bracket.</param>
|
||||
/// <param name="openBracket">The character for the opening bracket.</param>
|
||||
/// <param name="closingBracket">The character for the closing bracket.</param>
|
||||
/// <returns>Returns the offset of the opening bracket or -1 if no matching bracket was found.</returns>
|
||||
int SearchBracketBackward(IDocument document, int offset, char openBracket, char closingBracket);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the offset of the closing bracket in the block defined by offset skipping
|
||||
/// brackets in strings and comments.
|
||||
/// </summary>
|
||||
/// <param name="document">The document to search in.</param>
|
||||
/// <param name="offset">The offset of an position in the block or the offset of the opening bracket.</param>
|
||||
/// <param name="openBracket">The character for the opening bracket.</param>
|
||||
/// <param name="closingBracket">The character for the closing bracket.</param>
|
||||
/// <returns>Returns the offset of the closing bracket or -1 if no matching bracket was found.</returns>
|
||||
int SearchBracketForward(IDocument document, int offset, char openBracket, char closingBracket);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user