diff --git a/AvalonEdit/Documentation/ICSharpCode.AvalonEdit.shfbproj b/AvalonEdit/Documentation/ICSharpCode.AvalonEdit.shfbproj index f636ae24f..ad51dbd9a 100644 --- a/AvalonEdit/Documentation/ICSharpCode.AvalonEdit.shfbproj +++ b/AvalonEdit/Documentation/ICSharpCode.AvalonEdit.shfbproj @@ -1,4 +1,5 @@ - + + Documentation @@ -30,63 +31,28 @@ - 3.5 + .NET 4.0.30319 AvalonEdit - Copyright 2008-2010, Daniel Grunwald + Copyright 2008-2011, Daniel Grunwald Prototype - 4.0.0.0 + 4.1.0.0 - - - - - - - - - - - - - - - - - - - - - - - - - -{@CachedFrameworkCommentList} -{@CommentFileList} - - - - - - - - - - - - - - - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + +{@HelpFormatOutputPaths} + + - - - - + + + + + + + + + + + +{@CachedFrameworkCommentList} +{@CommentFileList} + + + -This is the main AvalonEdit namespace. -This namespace contains classes to show the code completion window. -This namespace contains the document model. + This is the main AvalonEdit namespace. + This namespace contains classes to show the code completion window. + This namespace contains the document model. The most important class here is TextDocument, which represents document that can be displayed and edited in the text editor. -This namespace is the home of the TextArea class. It manages user input and handles the caret and the selection. -This namespace contains the folding (code collapsing) implementation. -This namespace contains the engine for highlighting text documents (DocumentHighlighter). + This namespace is the home of the TextArea class. It manages user input and handles the caret and the selection. + This namespace contains the folding (code collapsing) implementation. + This namespace contains the engine for highlighting text documents (DocumentHighlighter). Additionally, the class HighlightingColorizer provides integration of the highlighting engine into the text editor GUI. -This namespace contains a document model for syntax highlighting definitions (.xshd files). -This namespace contains the logic for automatic indentation. -This namespace contains the text rendering infrastructure. -This namespace contains various utility classes. - -This namespace contains an error-tolerant XML parser with support for incremental parsing, only reparsing the changed regions of a TextDocument. -Snippets perform automatic text insertion. Snippets can be interactive after they were expanded, for example to allow the user to easily replace fields in the expanded snippet. + This namespace contains a document model for syntax highlighting definitions (.xshd files). + This namespace contains the logic for automatic indentation. + This namespace contains the text rendering infrastructure. + This namespace contains various utility classes. + + This namespace contains an error-tolerant XML parser with support for incremental parsing, only reparsing the changed regions of a TextDocument. + Snippets perform automatic text insertion. Snippets can be interactive after they were expanded, for example to allow the user to easily replace fields in the expanded snippet. + True Standard diff --git a/AvalonEdit/Documentation/Text Rendering.aml b/AvalonEdit/Documentation/Text Rendering.aml index d754407e2..2703277a2 100644 --- a/AvalonEdit/Documentation/Text Rendering.aml +++ b/AvalonEdit/Documentation/Text Rendering.aml @@ -153,9 +153,16 @@ These are the predefined layers: - Background layer: renders the background colors associated with the visual elementsSelection layer: renders the background of the selectionText layer: renders the TextLines that were constructed during the Measure step. - The text layer also serves as container for any inline UI elements. - Caret layer: renders a blinking caret + + Background layer: renders the background colors associated with the visual elements + Selection layer: renders the background of the selection + Text layer: renders the TextLines that were constructed during the Measure step. + Starting with AvalonEdit 4.1, the TextLayer uses child elements to draw the text: one DrawingVisual for each VisualLine. + + + Immediately after the text layer, any inline UI elements are placed as if they were separate layers. + + Caret layer: renders a blinking caret It's also possible to insert new layers into the TextView using the M:ICSharpCode.AvalonEdit.Rendering.TextView.InsertLayer(System.Windows.UIElement,ICSharpCode.AvalonEdit.Rendering.KnownLayer,ICSharpCode.AvalonEdit.Rendering.LayerInsertionPosition) method. diff --git a/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs b/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs index 9e09cd1bb..29d0473b1 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs @@ -25,10 +25,9 @@ namespace ICSharpCode.AvalonEdit.Highlighting { var segment = new TextSegment { StartOffset = 0, Length = document.TextLength }; string html = HtmlClipboard.CreateHtmlFragment(document, highlighter, segment, new HtmlOptions()); - Assert.AreEqual("using " + - "System.Text;
" + Environment.NewLine + + Assert.AreEqual("using System.Text;
" + Environment.NewLine + "    string " + - "text = SomeMethod();", html); + "text = SomeMethod();", html); } [Test] diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs b/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs index b7dc5f359..bbd26f601 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs @@ -3,6 +3,7 @@ using System; using System.Windows; +using System.Windows.Controls; using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Utils; @@ -28,6 +29,12 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion { this.CloseAutomatically = true; AttachEvents(); + + Rect caret = this.TextArea.Caret.CalculateCaretRectangle(); + Rect workingArea = System.Windows.Forms.Screen.FromPoint(caret.Location.ToSystemDrawing()).WorkingArea.ToWpf(); + + MaxHeight = workingArea.Height; + MaxWidth = Math.Min(workingArea.Width, Math.Max(1000, workingArea.Width * 0.6)); } /// @@ -63,4 +70,18 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion } } } + + /// + /// TemplateSelector for InsightWindow to replace plain string content by a TextBlock with TextWrapping. + /// + internal sealed class InsightWindowTemplateSelector : DataTemplateSelector + { + public override DataTemplate SelectTemplate(object item, DependencyObject container) + { + if (item is string) + return (DataTemplate)((FrameworkElement)container).FindResource("TextBlockTemplate"); + + return null; + } + } } diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.xaml b/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.xaml index 688e4b84f..213092632 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.xaml +++ b/AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.xaml @@ -2,6 +2,8 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:cc="clr-namespace:ICSharpCode.AvalonEdit.CodeCompletion" > + + + + + + @@ -100,10 +106,10 @@ - - + + diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentChangeEventArgs.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentChangeEventArgs.cs index acf1831a6..228669489 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentChangeEventArgs.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentChangeEventArgs.cs @@ -19,7 +19,7 @@ namespace ICSharpCode.AvalonEdit.Document public int Offset { get; private set; } /// - /// The text that was inserted. + /// The text that was removed. /// public string RemovedText { get; private set; } diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs index dfc7c0f96..b2108dba6 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs @@ -127,7 +127,6 @@ namespace ICSharpCode.AvalonEdit.Document return !left.Equals(right); } - /// public override string ToString() { return "[Offset=" + Offset.ToString(CultureInfo.InvariantCulture) + ", Length=" + Length.ToString(CultureInfo.InvariantCulture) + "]"; diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs index 15a9e9c37..8e1c2f550 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs @@ -51,7 +51,7 @@ namespace ICSharpCode.AvalonEdit.Editing AddBinding(EditingCommands.Delete, ModifierKeys.None, Key.Delete, OnDelete(EditingCommands.SelectRightByCharacter)); AddBinding(EditingCommands.DeleteNextWord, ModifierKeys.Control, Key.Delete, OnDelete(EditingCommands.SelectRightByWord)); AddBinding(EditingCommands.Backspace, ModifierKeys.None, Key.Back, OnDelete(EditingCommands.SelectLeftByCharacter)); - InputBindings.Add(new KeyBinding(EditingCommands.Backspace, Key.Back, ModifierKeys.Shift)); // make Shift-Backspace do the same as plain backspace + InputBindings.Add(TextAreaDefaultInputHandler.CreateFrozenKeyBinding(EditingCommands.Backspace, ModifierKeys.Shift, Key.Back)); // make Shift-Backspace do the same as plain backspace AddBinding(EditingCommands.DeletePreviousWord, ModifierKeys.Control, Key.Back, OnDelete(EditingCommands.SelectLeftByWord)); AddBinding(EditingCommands.EnterParagraphBreak, ModifierKeys.None, Key.Enter, OnEnter); AddBinding(EditingCommands.EnterLineBreak, ModifierKeys.Shift, Key.Enter, OnEnter); @@ -365,6 +365,8 @@ namespace ICSharpCode.AvalonEdit.Editing if (textArea != null && textArea.Document != null) { args.CanExecute = textArea.ReadOnlySectionProvider.CanInsert(textArea.Caret.Offset) && Clipboard.ContainsText(); + // WPF Clipboard.ContainsText() is safe to call without catching ExternalExceptions + // because it doesn't try to lock the clipboard - it just peeks inside with IsClipboardFormatAvailable(). args.Handled = true; } } @@ -373,15 +375,24 @@ namespace ICSharpCode.AvalonEdit.Editing { TextArea textArea = GetTextArea(target); if (textArea != null && textArea.Document != null) { - Debug.WriteLine( Clipboard.GetText(TextDataFormat.Html) ); + IDataObject dataObject; + try { + dataObject = Clipboard.GetDataObject(); + } catch (ExternalException) { + return; + } + if (dataObject == null) + return; + Debug.WriteLine( dataObject.GetData(DataFormats.Html) as string ); // convert text back to correct newlines for this document string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line); - string text = TextUtilities.NormalizeNewLines(Clipboard.GetText(), newLine); + string text = (string)dataObject.GetData(DataFormats.UnicodeText); + text = TextUtilities.NormalizeNewLines(text, newLine); if (!string.IsNullOrEmpty(text)) { - bool fullLine = textArea.Options.CutCopyWholeLine && Clipboard.ContainsData(LineSelectedType); - bool rectangular = Clipboard.ContainsData(RectangleSelection.RectangularSelectionDataType); + bool fullLine = textArea.Options.CutCopyWholeLine && dataObject.GetDataPresent(LineSelectedType); + bool rectangular = dataObject.GetDataPresent(RectangleSelection.RectangularSelectionDataType); if (fullLine) { DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line); if (textArea.ReadOnlySectionProvider.CanInsert(currentLine.Offset)) { diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingManager.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingManager.cs index 0dbf278a0..87ad45e8a 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingManager.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingManager.cs @@ -327,6 +327,7 @@ namespace ICSharpCode.AvalonEdit.Folding margin = new FoldingMargin() { FoldingManager = this }; generator = new FoldingElementGenerator() { FoldingManager = this }; textArea.LeftMargins.Add(margin); + textArea.TextView.Services.AddService(typeof(FoldingManager), this); // HACK: folding only works correctly when it has highest priority textArea.TextView.ElementGenerators.Insert(0, generator); textArea.Caret.PositionChanged += textArea_Caret_PositionChanged; @@ -363,6 +364,7 @@ namespace ICSharpCode.AvalonEdit.Folding textArea.Caret.PositionChanged -= textArea_Caret_PositionChanged; textArea.LeftMargins.Remove(margin); textArea.TextView.ElementGenerators.Remove(generator); + textArea.TextView.Services.RemoveService(typeof(FoldingManager)); margin = null; generator = null; textArea = null; diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingSection.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingSection.cs index 7df9196e9..f60e0db46 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingSection.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingSection.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Text; using System.Windows.Threading; using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Rendering; @@ -71,6 +72,72 @@ namespace ICSharpCode.AvalonEdit.Folding } } + /// + /// Gets the content of the collapsed lines as text. + /// + public string TextContent { + get { + return manager.document.GetText(StartOffset, EndOffset - StartOffset); + } + } + + /// + /// Gets the content of the collapsed lines as tooltip text. + /// + public string TooltipText { + get { + // This fixes SD-1394: + // Each line is checked for leading indentation whitespaces. If + // a line has the same or more indentation than the first line, + // it is reduced. If a line is less indented than the first line + // the indentation is removed completely. + // + // See the following example: + // line 1 + // line 2 + // line 3 + // line 4 + // + // is reduced to: + // line 1 + // line 2 + // line 3 + // line 4 + + var startLine = manager.document.GetLineByOffset(StartOffset); + var endLine = manager.document.GetLineByOffset(EndOffset); + var builder = new StringBuilder(); + + var current = startLine; + ISegment startIndent = TextUtilities.GetLeadingWhitespace(manager.document, startLine); + + while (current != endLine.NextLine) { + ISegment currentIndent = TextUtilities.GetLeadingWhitespace(manager.document, current); + + if (current == startLine && current == endLine) + builder.Append(manager.document.GetText(StartOffset, EndOffset - StartOffset)); + else if (current == startLine) { + if (current.EndOffset - StartOffset > 0) + builder.AppendLine(manager.document.GetText(StartOffset, current.EndOffset - StartOffset).TrimStart()); + } else if (current == endLine) { + if (startIndent.Length <= currentIndent.Length) + builder.Append(manager.document.GetText(current.Offset + startIndent.Length, EndOffset - current.Offset - startIndent.Length)); + else + builder.Append(manager.document.GetText(current.Offset + currentIndent.Length, EndOffset - current.Offset - currentIndent.Length)); + } else { + if (startIndent.Length <= currentIndent.Length) + builder.AppendLine(manager.document.GetText(current.Offset + startIndent.Length, current.Length - startIndent.Length)); + else + builder.AppendLine(manager.document.GetText(current.Offset + currentIndent.Length, current.Length - currentIndent.Length)); + } + + current = current.NextLine; + } + + return builder.ToString(); + } + } + /// /// Gets/Sets an additional object associated with this folding section. /// diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs index f613febe5..0e82d2966 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs @@ -84,6 +84,12 @@ namespace ICSharpCode.AvalonEdit.Highlighting { if (color == null) throw new ArgumentNullException("color"); + if (color.Foreground == null && color.FontStyle == null && color.FontWeight == null) { + // Optimization: don't split the HighlightingState when we're not changing + // any property. For example, the "Punctuation" color in C# is + // empty by default. + return; + } int startIndex = GetIndexForOffset(offset); int endIndex = GetIndexForOffset(offset + length); for (int i = startIndex; i < endIndex; i++) { diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs index cbeee2028..31c225140 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs @@ -127,12 +127,14 @@ namespace ICSharpCode.AvalonEdit.Highlighting HtmlClipboard.EscapeHtml(w, document.GetText(textOffset, newOffset - textOffset), options); } textOffset = Math.Max(textOffset, newOffset); - if (e.IsEnd) { - w.Write(""); - } else { - w.Write("'); + if (options.ColorNeedsSpanForStyling(e.Color)) { + if (e.IsEnd) { + w.Write(""); + } else { + w.Write("'); + } } } HtmlClipboard.EscapeHtml(w, document.GetText(textOffset, endOffset - textOffset), options); diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs index 236664a8a..1c55bd8dd 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs @@ -137,6 +137,8 @@ namespace ICSharpCode.AvalonEdit.Highlighting HighlightedLine hl = highlighter.HighlightLine(lineNumberBeingColorized); lineNumberBeingColorized = 0; foreach (HighlightedSection section in hl.Sections) { + if (IsEmptyColor(section.Color)) + continue; ChangeLinePart(section.Offset, section.Offset + section.Length, visualLineElement => ApplyColorToElement(visualLineElement, section.Color)); } @@ -144,6 +146,18 @@ namespace ICSharpCode.AvalonEdit.Highlighting this.lastColorizedLine = line; } + /// + /// Gets whether the color is empty (has no effect on a VisualLineTextElement). + /// For example, the C# "Punctuation" is an empty color. + /// + bool IsEmptyColor(HighlightingColor color) + { + if (color == null) + return true; + return color.Background == null && color.Foreground == null + && color.FontStyle == null && color.FontWeight == null; + } + /// /// Applies a highlighting color to a visual line element. /// diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlClipboard.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlClipboard.cs index 387ebd9f3..43658d8e8 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlClipboard.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlClipboard.cs @@ -187,5 +187,15 @@ namespace ICSharpCode.AvalonEdit.Highlighting writer.Write(color.ToCss()); writer.Write("\""); } + + /// + /// Gets whether the color needs to be written out to HTML. + /// + public virtual bool ColorNeedsSpanForStyling(HighlightingColor color) + { + if (color == null) + throw new ArgumentNullException("color"); + return !string.IsNullOrEmpty(color.ToCss()); + } } } diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/ASPX.xshd b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/ASPX.xshd index a72187941..bd0c922ac 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/ASPX.xshd +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/ASPX.xshd @@ -1,6 +1,6 @@ - + diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CSS-Mode.xshd b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CSS-Mode.xshd new file mode 100644 index 000000000..3ef562f0d --- /dev/null +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CSS-Mode.xshd @@ -0,0 +1,57 @@ + + + + + + + + + + + + + /\* + \*/ + + + \{ + \} + + + \# + \s + + [\d\w] + + + + + /\* + \*/ + + + \: + \;|(?=\}) + + + " + " + + + + + + ' + ' + + + + + + + + + diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CSharp-Mode.xshd b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CSharp-Mode.xshd index bc23611e2..798d6a374 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CSharp-Mode.xshd +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/CSharp-Mode.xshd @@ -5,7 +5,7 @@ - + @@ -43,20 +43,21 @@ \# - - if - else - elif - endif - define - undef - warning - error - line - region - endregion - pragma - + + + (define|undef|if|elif|else|endif|line)\b + + + + // + + + + + + (region|endregion|error|warning|pragma)\b + + diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/HTML-Mode.xshd b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/HTML-Mode.xshd index e23d6a624..d3c31b5e2 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/HTML-Mode.xshd +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/HTML-Mode.xshd @@ -4,11 +4,11 @@ - - - - - + + + + + @@ -23,25 +23,25 @@ <!-- --> - - <script> - </script> + + <script> + </script> - - <script\ lang="JavaScript"> - </script> + + <script\ lang="JavaScript"> + </script> - - <script\ lang="JScript"> - </script> + + <script\ lang="JScript"> + </script> - - <script\ lang="VBScript"> - </script> + + <script\ lang="VBScript"> + </script> - - <script[^\w\d_] - </script> + + <script[^\w\d_] + </script> < diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/Resources.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/Resources.cs index 2bdd2e639..594417e04 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/Resources.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/Resources/Resources.cs @@ -25,10 +25,11 @@ namespace ICSharpCode.AvalonEdit.Highlighting hlm.RegisterHighlighting("JavaScript", new[] { ".js" }, "JavaScript-Mode.xshd"); hlm.RegisterHighlighting("HTML", new[] { ".htm", ".html" }, "HTML-Mode.xshd"); - hlm.RegisterHighlighting("ASP/XHTML", new[] { ".asp", ".aspx", ".asax", ".asmx" }, "ASPX.xshd"); + hlm.RegisterHighlighting("ASP/XHTML", new[] { ".asp", ".aspx", ".asax", ".asmx", ".ascx", ".master" }, "ASPX.xshd"); hlm.RegisterHighlighting("Boo", new[] { ".boo" }, "Boo.xshd"); hlm.RegisterHighlighting("Coco", new[] { ".atg" }, "Coco-Mode.xshd"); + hlm.RegisterHighlighting("CSS", new[] { ".css" }, "CSS-Mode.xshd"); hlm.RegisterHighlighting("C++", new[] { ".c", ".h", ".cc", ".cpp" , ".hpp" }, "CPP-Mode.xshd"); hlm.RegisterHighlighting("Java", new[] { ".java" }, "Java-Mode.xshd"); hlm.RegisterHighlighting("Patch", new[] { ".patch", ".diff" }, "Patch-Mode.xshd"); diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj index ee5e00268..281e4cd27 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj +++ b/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj @@ -407,4 +407,7 @@ + + + \ No newline at end of file diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Properties/GlobalAssemblyInfo.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Properties/GlobalAssemblyInfo.cs index 9eb048c2a..64a2fa0e7 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Properties/GlobalAssemblyInfo.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Properties/GlobalAssemblyInfo.cs @@ -18,7 +18,7 @@ using System.Reflection; [assembly: AssemblyProduct("SharpDevelop")] [assembly: AssemblyCopyright("2000-2011 AlphaSierraPapa for the SharpDevelop Team")] [assembly: AssemblyVersion(RevisionClass.Major + "." + RevisionClass.Minor + "." + RevisionClass.Build + "." + RevisionClass.Revision)] -[assembly: AssemblyInformationalVersion(RevisionClass.FullVersion + "-3301c6c4")] +[assembly: AssemblyInformationalVersion(RevisionClass.FullVersion + "-ae3458d9")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly", @@ -29,8 +29,8 @@ internal static class RevisionClass public const string Major = "4"; public const string Minor = "1"; public const string Build = "0"; - public const string Revision = "7411"; - public const string VersionName = "alpha"; + public const string Revision = "7920"; + public const string VersionName = null; - public const string FullVersion = Major + "." + Minor + "." + Build + ".7411-alpha"; + public const string FullVersion = Major + "." + Minor + "." + Build + ".7920"; } diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs index 354281fce..60a647c50 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/LinkElementGenerator.cs @@ -126,7 +126,6 @@ namespace ICSharpCode.AvalonEdit.Rendering { } - /// protected override Uri GetUriFromMatch(Match match) { return new Uri("mailto:" + match.Value); diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs index e81afbb22..071801062 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/NewLineElementGenerator.cs @@ -26,7 +26,6 @@ namespace ICSharpCode.AvalonEdit.Rendering { } - /// public override int GetFirstInterestedOffset(int startOffset) { DocumentLine lastDocumentLine = CurrentContext.VisualLine.LastDocumentLine; @@ -36,7 +35,6 @@ namespace ICSharpCode.AvalonEdit.Rendering return -1; } - /// public override VisualLineElement ConstructElement(int offset) { string newlineText; diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs index 1ad5dcb20..0a27deb82 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/SingleCharacterElementGenerator.cs @@ -56,7 +56,6 @@ namespace ICSharpCode.AvalonEdit.Rendering this.ShowBoxForControlCharacters = options.ShowBoxForControlCharacters; } - /// public override int GetFirstInterestedOffset(int startOffset) { DocumentLine endLine = CurrentContext.VisualLine.LastDocumentLine; @@ -83,7 +82,6 @@ namespace ICSharpCode.AvalonEdit.Rendering return -1; } - /// public override VisualLineElement ConstructElement(int offset) { char c = CurrentContext.Document.GetCharAt(offset); @@ -230,6 +228,14 @@ namespace ICSharpCode.AvalonEdit.Rendering sealed class SpecialCharacterTextRun : FormattedTextRun { + static readonly SolidColorBrush darkGrayBrush; + + static SpecialCharacterTextRun() + { + darkGrayBrush = new SolidColorBrush(Color.FromArgb(200, 128, 128, 128)); + darkGrayBrush.Freeze(); + } + public SpecialCharacterTextRun(FormattedTextElement element, TextRunProperties properties) : base(element, properties) { @@ -237,10 +243,10 @@ namespace ICSharpCode.AvalonEdit.Rendering public override void Draw(DrawingContext drawingContext, Point origin, bool rightToLeft, bool sideways) { - Point newOrigin = new Point(origin.X + 1, origin.Y); - var metrics = Format(double.PositiveInfinity); - Rect r = new Rect(newOrigin.X + 1, newOrigin.Y - metrics.Baseline, metrics.Width + 1, metrics.Height); - drawingContext.DrawRoundedRectangle(Brushes.DarkGray, null, r, 2.5, 2.5); + Point newOrigin = new Point(origin.X + 1.5, origin.Y); + var metrics = base.Format(double.PositiveInfinity); + Rect r = new Rect(newOrigin.X - 0.5, newOrigin.Y - metrics.Baseline, metrics.Width + 2, metrics.Height); + drawingContext.DrawRoundedRectangle(darkGrayBrush, null, r, 2.5, 2.5); base.Draw(drawingContext, newOrigin, rightToLeft, sideways); } diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextLayer.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextLayer.cs index e2b06e337..469884669 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextLayer.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextLayer.cs @@ -33,10 +33,38 @@ namespace ICSharpCode.AvalonEdit.Rendering { } - protected override void OnRender(DrawingContext drawingContext) + List visuals = new List(); + + internal void SetVisualLines(ICollection visualLines) + { + foreach (VisualLineDrawingVisual v in visuals) { + if (v.VisualLine.IsDisposed) + RemoveVisualChild(v); + } + visuals.Clear(); + foreach (VisualLine newLine in visualLines) { + VisualLineDrawingVisual v = newLine.Render(); + if (!v.IsAdded) { + AddVisualChild(v); + v.IsAdded = true; + } + visuals.Add(v); + } + InvalidateArrange(); + } + + protected override int VisualChildrenCount { + get { return visuals.Count; } + } + + protected override Visual GetVisualChild(int index) + { + return visuals[index]; + } + + protected override void ArrangeCore(Rect finalRect) { - base.OnRender(drawingContext); - textView.RenderTextLayer(drawingContext); + textView.ArrangeTextLayer(visuals); } } } diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs index 68483921b..db13efe53 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs @@ -833,7 +833,6 @@ namespace ICSharpCode.AvalonEdit.Rendering MeasureInlineObjects(); InvalidateVisual(); // = InvalidateArrange+InvalidateRender - textLayer.InvalidateVisual(); double maxWidth; if (document == null) { @@ -862,6 +861,8 @@ namespace ICSharpCode.AvalonEdit.Rendering } } + textLayer.SetVisualLines(visibleVisualLines); + SetScrollData(availableSize, new Size(maxWidth, heightTreeHeight), scrollOffset); @@ -1153,14 +1154,16 @@ namespace ICSharpCode.AvalonEdit.Rendering } } - internal void RenderTextLayer(DrawingContext drawingContext) + internal void ArrangeTextLayer(IList visuals) { Point pos = new Point(-scrollOffset.X, -clippedPixelsOnTop); - foreach (VisualLine visualLine in allVisualLines) { - foreach (TextLine textLine in visualLine.TextLines) { - textLine.Draw(drawingContext, pos, InvertAxes.None); - pos.Y += textLine.Height; + foreach (VisualLineDrawingVisual visual in visuals) { + TranslateTransform t = visual.Transform as TranslateTransform; + if (t == null || t.X != pos.X || t.Y != pos.Y) { + visual.Transform = new TranslateTransform(pos.X, pos.Y); + visual.Transform.Freeze(); } + pos.Y += visual.Height; } } #endregion diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs index 53b606521..4d8ef56fc 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLine.cs @@ -1,6 +1,7 @@ // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) +using System.Windows.Media; using ICSharpCode.AvalonEdit.Utils; using System; using System.Collections.Generic; @@ -424,5 +425,34 @@ namespace ICSharpCode.AvalonEdit.Rendering { return true; } + + VisualLineDrawingVisual visual; + + internal VisualLineDrawingVisual Render() + { + if (visual == null) + visual = new VisualLineDrawingVisual(this); + return visual; + } + } + + sealed class VisualLineDrawingVisual : DrawingVisual + { + public readonly VisualLine VisualLine; + public readonly double Height; + internal bool IsAdded; + + public VisualLineDrawingVisual(VisualLine visualLine) + { + this.VisualLine = visualLine; + var drawingContext = RenderOpen(); + double pos = 0; + foreach (TextLine textLine in visualLine.TextLines) { + textLine.Draw(drawingContext, new Point(0, pos), InvertAxes.None); + pos += textLine.Height; + } + this.Height = pos; + drawingContext.Close(); + } } } diff --git a/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs b/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs index db23c5bb2..fb984c13a 100644 --- a/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs +++ b/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs @@ -343,9 +343,38 @@ namespace ICSharpCode.AvalonEdit.Utils return -1; } + /// + /// Gets the the first index so that all values from the result index to + /// are equal. + /// + public int GetStartOfRun(int index) + { + if (index < 0 || index >= this.Count) + throw new ArgumentOutOfRangeException("index", index, "Value must be between 0 and " + (this.Count - 1)); + int indexInRun = index; + GetNode(ref indexInRun); + return index - indexInRun; + } + + /// + /// Gets the first index after so that the value at the result index is not + /// equal to the value at . + /// That is, this method returns the exclusive end index of the run of equal values. + /// + public int GetEndOfRun(int index) + { + if (index < 0 || index >= this.Count) + throw new ArgumentOutOfRangeException("index", index, "Value must be between 0 and " + (this.Count - 1)); + int indexInRun = index; + int runLength = GetNode(ref indexInRun).count; + return index - indexInRun + runLength; + } + /// /// Gets the number of elements after that have the same value as each other. /// + [Obsolete("This method may be confusing as it returns only the remaining run length after index. " + + "Use GetStartOfRun/GetEndOfRun instead.")] public int GetRunLength(int index) { if (index < 0 || index >= this.Count)