diff --git a/samples/AvalonEdit.Sample/Window1.xaml.cs b/samples/AvalonEdit.Sample/Window1.xaml.cs index 97198b5aec..35fc9bde94 100644 --- a/samples/AvalonEdit.Sample/Window1.xaml.cs +++ b/samples/AvalonEdit.Sample/Window1.xaml.cs @@ -157,14 +157,17 @@ namespace AvalonEdit.Sample switch (textEditor.SyntaxHighlighting.Name) { case "XML": foldingStrategy = new XmlFoldingStrategy(); + textEditor.TextArea.IndentationStrategy = new ICSharpCode.AvalonEdit.Indentation.DefaultIndentationStrategy(); break; case "C#": case "C++": case "PHP": case "Java": + textEditor.TextArea.IndentationStrategy = new ICSharpCode.AvalonEdit.Indentation.CSharp.CSharpIndentationStrategy(textEditor.Options); foldingStrategy = new BraceFoldingStrategy(); break; default: + textEditor.TextArea.IndentationStrategy = new ICSharpCode.AvalonEdit.Indentation.DefaultIndentationStrategy(); foldingStrategy = null; break; } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj index 4bd679437f..9724835fa2 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj @@ -60,7 +60,6 @@ - Form @@ -80,6 +79,11 @@ + + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1} + ICSharpCode.AvalonEdit + False + {2D18BE89-D210-49EB-A9DD-2246FBB3DF6D} ICSharpCode.TextEditor diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs index 8df8fe5a99..0002be7a99 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs @@ -6,17 +6,13 @@ // using System; -using System.Collections; -using System.Collections.Generic; using System.Diagnostics; -using System.Drawing; using System.Linq; using System.Text; -using ICSharpCode.NRefactory; +using ICSharpCode.AvalonEdit.Indentation.CSharp; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; -using ICSharpCode.SharpDevelop.Dom.Refactoring; using ICSharpCode.SharpDevelop.Editor; namespace CSharpBinding.FormattingStrategy @@ -33,12 +29,9 @@ namespace CSharpBinding.FormattingStrategy int lineNr = line.LineNumber; DocumentAccessor acc = new DocumentAccessor(editor.Document, lineNr, lineNr); - IndentationSettings set = new IndentationSettings(); - set.IndentString = editor.Options.IndentationString; - set.LeaveEmptyLines = false; - IndentationReformatter r = new IndentationReformatter(); - - r.Reformat(acc, set); + CSharpIndentationStrategy indentStrategy = new CSharpIndentationStrategy(); + indentStrategy.IndentationString = editor.Options.IndentationString; + indentStrategy.Indent(acc, false); string t = acc.Text; if (t.Length == 0) { @@ -49,11 +42,10 @@ namespace CSharpBinding.FormattingStrategy public override void IndentLines(ITextEditor editor, int beginLine, int endLine) { - IndentationSettings set = new IndentationSettings(); - set.IndentString = editor.Options.IndentationString; - IndentationReformatter r = new IndentationReformatter(); DocumentAccessor acc = new DocumentAccessor(editor.Document, beginLine, endLine); - r.Reformat(acc, set); + CSharpIndentationStrategy indentStrategy = new CSharpIndentationStrategy(); + indentStrategy.IndentationString = editor.Options.IndentationString; + indentStrategy.Indent(acc, true); } #endregion diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/DocumentAccessor.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/DocumentAccessor.cs index b5b8a4131b..cb6ca9ef2b 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/DocumentAccessor.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/DocumentAccessor.cs @@ -1,110 +1,85 @@ // // // -// +// // $Revision$ // using System; -using System.Collections.Generic; -using System.IO; - -using ICSharpCode.SharpDevelop; +using ICSharpCode.AvalonEdit.Indentation.CSharp; using ICSharpCode.SharpDevelop.Editor; namespace CSharpBinding.FormattingStrategy { - /// - /// Interface used for the indentation class to access the document. - /// - public interface IDocumentAccessor - { - /// Gets if something was changed in the document. - bool Dirty { get; } - /// Gets if the current line is read only (because it is not in the - /// selected text region) - bool ReadOnly { get; } - /// Gets the number of the current line. - int LineNumber { get; } - /// Gets/Sets the text of the current line. - string Text { get; set; } - /// Advances to the next line. - bool Next(); - } - - #region DocumentAccessor /// /// Adapter IDocumentAccessor -> IDocument /// public sealed class DocumentAccessor : IDocumentAccessor { - IDocument doc; - - int minLine; - int maxLine; - int changedLines = 0; + readonly IDocument doc; + readonly int minLine; + readonly int maxLine; + /// + /// Creates a new DocumentAccessor. + /// public DocumentAccessor(IDocument document) { + if (document == null) + throw new ArgumentNullException("document"); doc = document; this.minLine = 1; this.maxLine = doc.TotalNumberOfLines; } + /// + /// Creates a new DocumentAccessor that indents only a part of the document. + /// public DocumentAccessor(IDocument document, int minLine, int maxLine) { + if (document == null) + throw new ArgumentNullException("document"); doc = document; this.minLine = minLine; this.maxLine = maxLine; } - int num = 0; - bool dirty; + int num; string text; IDocumentLine line; + /// public bool ReadOnly { get { return num < minLine; } } - public bool Dirty { - get { - return dirty; - } - } - + /// public int LineNumber { get { return num; } } - public int ChangedLines { - get { - return changedLines; - } - } - - bool lineDirty = false; + bool lineDirty; + /// public string Text { get { return text; } set { if (num < minLine) return; text = value; - dirty = true; lineDirty = true; } } + /// public bool Next() { if (lineDirty) { DocumentUtilitites.SmartReplaceLine(doc, line, text); lineDirty = false; - ++changedLines; } ++num; if (num > maxLine) return false; @@ -113,146 +88,4 @@ namespace CSharpBinding.FormattingStrategy return true; } } - #endregion - - #region FileAccessor - public sealed class FileAccessor : IDisposable, IDocumentAccessor - { - public bool Dirty { - get { - return dirty; - } - } - - public bool ReadOnly { - get { - return false; - } - } - - FileStream f; - StreamReader r; - List lines = new List(); - bool dirty = false; - - string filename; - public FileAccessor(string filename) - { - this.filename = filename; - f = new FileStream(filename, FileMode.Open, FileAccess.Read); - r = ICSharpCode.TextEditor.Util.FileReader.OpenStream(f, ParserService.DefaultFileEncoding); - } - - int num = 0; - - public int LineNumber { - get { return num; } - } - - - string text = ""; - - public string Text { - get { - return text; - } - set { - dirty = true; - text = value; - } - } - - public bool Next() - { - if (num > 0) { - lines.Add(text); - } - text = r.ReadLine(); - ++num; - return text != null; - } - - void IDisposable.Dispose() - { - Close(); - } - - public void Close() - { - System.Text.Encoding encoding = r.CurrentEncoding; - r.Close(); - f.Close(); - if (dirty) { - f = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None); - using (StreamWriter w = new StreamWriter(f, encoding)) { - foreach (string line in lines) { - w.WriteLine(line); - } - } - f.Close(); - } - } - } - #endregion - - #region StringAccessor - public sealed class StringAccessor : IDocumentAccessor - { - public bool Dirty { - get { - return dirty; - } - } - - public bool ReadOnly { - get { - return false; - } - } - - StringReader r; - StringWriter w; - bool dirty = false; - - public string CodeOutput { - get { - return w.ToString(); - } - } - - public StringAccessor(string code) - { - r = new StringReader(code); - w = new StringWriter(); - } - - int num = 0; - - public int LineNumber { - get { return num; } - } - - string text = ""; - - public string Text { - get { - return text; - } - set { - dirty = true; - text = value; - } - } - - public bool Next() - { - if (num > 0) { - w.WriteLine(text); - } - text = r.ReadLine(); - ++num; - return text != null; - } - } - #endregion } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj index 2a9d3b9b8c..84d891396c 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj @@ -206,6 +206,9 @@ + + + @@ -381,6 +384,7 @@ + diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Indentation/CSharp/CSharpIndentationStrategy.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Indentation/CSharp/CSharpIndentationStrategy.cs new file mode 100644 index 0000000000..cadae9aa0e --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Indentation/CSharp/CSharpIndentationStrategy.cs @@ -0,0 +1,84 @@ +// +// +// +// +// $Revision$ +// + +using System; +using ICSharpCode.AvalonEdit.Document; + +namespace ICSharpCode.AvalonEdit.Indentation.CSharp +{ + /// + /// Smart indentation for C#. + /// + public class CSharpIndentationStrategy : DefaultIndentationStrategy + { + /// + /// Creates a new CSharpIndentationStrategy. + /// + public CSharpIndentationStrategy() + { + } + + /// + /// Creates a new CSharpIndentationStrategy and initializes the settings using the text editor options. + /// + public CSharpIndentationStrategy(TextEditorOptions options) + { + this.IndentationString = options.IndentationString; + } + + string indentationString = "\t"; + + /// + /// Gets/Sets the indentation string. + /// + public string IndentationString { + get { return indentationString; } + set { + if (string.IsNullOrEmpty(value)) + throw new ArgumentException("Indentation string must not be null or empty"); + indentationString = value; + } + } + + /// + /// Performs indentation using the specified document accessor. + /// + /// Object used for accessing the document line-by-line + /// Specifies whether empty lines should be kept + public void Indent(IDocumentAccessor document, bool keepEmptyLines) + { + if (document == null) + throw new ArgumentNullException("document"); + IndentationSettings settings = new IndentationSettings(); + settings.IndentString = this.IndentationString; + settings.LeaveEmptyLines = keepEmptyLines; + + IndentationReformatter r = new IndentationReformatter(); + r.Reformat(document, settings); + } + + /// + public override void IndentLine(TextDocument document, DocumentLine line) + { + int lineNr = line.LineNumber; + TextDocumentAccessor acc = new TextDocumentAccessor(document, lineNr, lineNr); + Indent(acc, false); + + string t = acc.Text; + if (t.Length == 0) { + // use AutoIndentation for new lines in comments / verbatim strings. + base.IndentLine(document, line); + } + } + + /// + public override void IndentLines(TextDocument document, int beginLine, int endLine) + { + Indent(new TextDocumentAccessor(document, beginLine, endLine), true); + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Indentation/CSharp/DocumentAccessor.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Indentation/CSharp/DocumentAccessor.cs new file mode 100644 index 0000000000..b75524530f --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Indentation/CSharp/DocumentAccessor.cs @@ -0,0 +1,111 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.IO; + +using ICSharpCode.AvalonEdit.Document; + +namespace ICSharpCode.AvalonEdit.Indentation.CSharp +{ + /// + /// Interface used for the indentation class to access the document. + /// + public interface IDocumentAccessor + { + /// Gets if the current line is read only (because it is not in the + /// selected text region) + bool ReadOnly { get; } + /// Gets the number of the current line. + int LineNumber { get; } + /// Gets/Sets the text of the current line. + string Text { get; set; } + /// Advances to the next line. + bool Next(); + } + + #region TextDocumentAccessor + /// + /// Adapter IDocumentAccessor -> TextDocument + /// + public sealed class TextDocumentAccessor : IDocumentAccessor + { + readonly TextDocument doc; + readonly int minLine; + readonly int maxLine; + + /// + /// Creates a new TextDocumentAccessor. + /// + public TextDocumentAccessor(TextDocument document) + { + if (document == null) + throw new ArgumentNullException("document"); + doc = document; + this.minLine = 1; + this.maxLine = doc.LineCount; + } + + /// + /// Creates a new TextDocumentAccessor that indents only a part of the document. + /// + public TextDocumentAccessor(TextDocument document, int minLine, int maxLine) + { + if (document == null) + throw new ArgumentNullException("document"); + doc = document; + this.minLine = minLine; + this.maxLine = maxLine; + } + + int num; + string text; + DocumentLine line; + + /// + public bool ReadOnly { + get { + return num < minLine; + } + } + + /// + public int LineNumber { + get { + return num; + } + } + + bool lineDirty; + + /// + public string Text { + get { return text; } + set { + if (num < minLine) return; + text = value; + lineDirty = true; + } + } + + /// + public bool Next() + { + if (lineDirty) { + doc.Replace(line, text); + lineDirty = false; + } + ++num; + if (num > maxLine) return false; + line = doc.GetLineByNumber(num); + text = doc.GetText(line); + return true; + } + } + #endregion +} diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/Indentation.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Indentation/CSharp/IndentationReformatter.cs similarity index 88% rename from src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/Indentation.cs rename to src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Indentation/CSharp/IndentationReformatter.cs index 1d4566bdf8..3f1415c8f2 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/Indentation.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Indentation/CSharp/IndentationReformatter.cs @@ -7,23 +7,24 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text; -namespace CSharpBinding.FormattingStrategy +namespace ICSharpCode.AvalonEdit.Indentation.CSharp { - public sealed class IndentationSettings + sealed class IndentationSettings { public string IndentString = "\t"; /// Leave empty lines empty. public bool LeaveEmptyLines = true; } - public sealed class IndentationReformatter + sealed class IndentationReformatter { /// /// An indentation block. Tracks the state of the indentation. /// - public struct Block + struct Block { /// /// The indentation outside of the block. @@ -81,13 +82,13 @@ namespace CSharpBinding.FormattingStrategy public void Indent(IndentationSettings set) { - Indent(set, set.IndentString); + Indent(set.IndentString); } - public void Indent(IndentationSettings set, string str) + public void Indent(string indentationString) { OuterIndent = InnerIndent; - InnerIndent += str; + InnerIndent += indentationString; Continuation = false; ResetOneLineBlock(); LastWord = ""; @@ -95,8 +96,10 @@ namespace CSharpBinding.FormattingStrategy public override string ToString() { - return string.Format("[Block StartLine={0}, LastWord='{1}', Continuation={2}, OneLineBlock={3}, PreviousOneLineBlock={4}]", - this.StartLine, this.LastWord, this.Continuation, this.OneLineBlock, this.PreviousOneLineBlock); + return string.Format( + CultureInfo.InvariantCulture, + "[Block StartLine={0}, LastWord='{1}', Continuation={2}, OneLineBlock={3}, PreviousOneLineBlock={4}]", + this.StartLine, this.LastWord, this.Continuation, this.OneLineBlock, this.PreviousOneLineBlock); } } @@ -104,15 +107,15 @@ namespace CSharpBinding.FormattingStrategy Stack blocks; // blocks contains all blocks outside of the current Block block; // block is the current block - bool inString = false; - bool inChar = false; - bool verbatim = false; - bool escape = false; + bool inString; + bool inChar; + bool verbatim; + bool escape; - bool lineComment = false; - bool blockComment = false; + bool lineComment; + bool blockComment; - char lastRealChar = ' '; // last non-comment char + char lastRealChar; // last non-comment char public void Reformat(IDocumentAccessor doc, IndentationSettings set) { @@ -271,7 +274,7 @@ namespace CSharpBinding.FormattingStrategy blocks.Push(block); block.StartLine = doc.LineNumber; if (block.LastWord == "switch") { - block.Indent(set, set.IndentString + set.IndentString); + block.Indent(set.IndentString + set.IndentString); /* oldBlock refers to the previous line, not the previous block * The block we want is not available anymore because it was never pushed. * } else if (oldBlock.OneLineBlock) { @@ -306,8 +309,7 @@ namespace CSharpBinding.FormattingStrategy block.InnerIndent = block.OuterIndent; else block.StartLine = doc.LineNumber; - block.Indent(set, - Repeat(set.IndentString, oldBlock.OneLineBlock) + + block.Indent(Repeat(set.IndentString, oldBlock.OneLineBlock) + (oldBlock.Continuation ? set.IndentString : "") + (i == line.Length - 1 ? set.IndentString : new String(' ', i + 1))); block.Bracket = c; @@ -331,7 +333,10 @@ namespace CSharpBinding.FormattingStrategy block.ResetOneLineBlock(); break; case ':': - if (block.LastWord == "case" || line.StartsWith("case ") || line.StartsWith(block.LastWord + ":")) { + if (block.LastWord == "case" + || line.StartsWith("case ", StringComparison.Ordinal) + || line.StartsWith(block.LastWord + ":", StringComparison.Ordinal)) + { block.Continuation = false; block.ResetOneLineBlock(); } @@ -352,7 +357,7 @@ namespace CSharpBinding.FormattingStrategy if (startInString) return; if (startInComment && line[0] != '*') return; - if (doc.Text.StartsWith("//\t") || doc.Text == "//") + if (doc.Text.StartsWith("//\t", StringComparison.Ordinal) || doc.Text == "//") return; if (line[0] == '}') { @@ -372,7 +377,7 @@ namespace CSharpBinding.FormattingStrategy if (line[0] == ':') { oldBlock.Continuation = true; } else if (lastRealChar == ':' && indent.Length >= set.IndentString.Length) { - if (block.LastWord == "case" || line.StartsWith("case ") || line.StartsWith(block.LastWord + ":")) + if (block.LastWord == "case" || line.StartsWith("case ", StringComparison.Ordinal) || line.StartsWith(block.LastWord + ":", StringComparison.Ordinal)) indent.Remove(indent.Length - set.IndentString.Length, set.IndentString.Length); } else if (lastRealChar == ')') { if (IsSingleStatementKeyword(block.LastWord)) { @@ -422,7 +427,7 @@ namespace CSharpBinding.FormattingStrategy indent.Append(' '); if (indent.Length != (doc.Text.Length - line.Length) || - !doc.Text.StartsWith(indent.ToString()) || + !doc.Text.StartsWith(indent.ToString(), StringComparison.Ordinal) || Char.IsWhiteSpace(doc.Text[indent.Length])) { doc.Text = indent.ToString() + line; @@ -441,7 +446,7 @@ namespace CSharpBinding.FormattingStrategy return b.ToString(); } - bool IsSingleStatementKeyword(string keyword) + static bool IsSingleStatementKeyword(string keyword) { switch (keyword) { case "if": @@ -457,13 +462,13 @@ namespace CSharpBinding.FormattingStrategy } } - bool TrimEnd(IDocumentAccessor doc) + static bool TrimEnd(IDocumentAccessor doc) { string line = doc.Text; if (!Char.IsWhiteSpace(line[line.Length - 1])) return false; // one space after an empty comment is allowed - if (line.EndsWith("// ") || line.EndsWith("* ")) + if (line.EndsWith("// ", StringComparison.Ordinal) || line.EndsWith("* ", StringComparison.Ordinal)) return false; doc.Text = line.TrimEnd(); diff --git a/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs b/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs index 0761a94a14..c4bc4e8ed1 100644 --- a/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs +++ b/src/Main/Base/Project/Src/Gui/WorkbenchSingleton.cs @@ -122,9 +122,7 @@ namespace ICSharpCode.SharpDevelop.Gui ApplicationStateInfoService.UnregisterStateGetter(activeContentState); - if (WorkbenchUnloaded != null) { - WorkbenchUnloaded(null, EventArgs.Empty); - } + WorkbenchUnloaded(null, EventArgs.Empty); FileService.Unload(); } @@ -266,7 +264,7 @@ namespace ICSharpCode.SharpDevelop.Gui delegate { Timer t = new Timer(); t.Interval = delayMilliseconds; - t.Tick += delegate { + t.Tick += delegate { t.Stop(); t.Dispose(); method(); @@ -278,19 +276,17 @@ namespace ICSharpCode.SharpDevelop.Gui static void OnWorkbenchCreated() { - if (WorkbenchCreated != null) { - WorkbenchCreated(null, EventArgs.Empty); - } + WorkbenchCreated(null, EventArgs.Empty); } /// /// Is called, when the workbench is created /// - public static event EventHandler WorkbenchCreated; + public static event EventHandler WorkbenchCreated = delegate {}; /// /// Is called, when the workbench is unloaded /// - public static event EventHandler WorkbenchUnloaded; + public static event EventHandler WorkbenchUnloaded = delegate {}; } }