From 73dda200d7600528de6b7952c1ab531f480e30f8 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 21 Jul 2013 18:59:28 +0200 Subject: [PATCH] Add basic rich-text support to AvalonEdit. --- SharpDevelop.Tests.sln | 84 ++-- .../Gui/Commands/AnalyzeCodeQualityCommand.cs | 4 +- ...rideEqualsGetHashCodeMethodsDialog.xaml.cs | 2 +- .../Project/Src/PackageManagementWorkbench.cs | 2 +- .../Highlighting/HtmlClipboardTests.cs | 6 +- .../Utils/CompressingTreeListTests.cs | 36 +- .../Document/DocumentTextWriter.cs | 69 +++ .../Document/NewLineFinder.cs | 4 +- .../Document/TextDocumentWeakEventManager.cs | 1 + .../Highlighting/HighlightedInlineBuilder.cs | 11 +- .../Highlighting/HighlightedLine.cs | 61 ++- .../Highlighting/HighlightingBrush.cs | 26 ++ .../Highlighting/HighlightingColor.cs | 72 ++- .../Highlighting/HighlightingColorizer.cs | 11 +- .../Highlighting/HtmlClipboard.cs | 103 ---- .../Highlighting/HtmlOptions.cs | 62 +++ .../Highlighting/HtmlRichTextWriter.cs | 236 ++++++++++ .../Highlighting/RichTextColorizer.cs | 39 ++ .../Highlighting/RichTextModel.cs | 165 +++++++ .../Highlighting/RichTextModelWriter.cs | 118 +++++ .../ICSharpCode.AvalonEdit.csproj | 8 + .../Search/SearchPanel.cs | 1 + .../Utils/CompressingTreeList.cs | 22 +- .../Utils/PlainRichTextWriter.cs | 125 +++++ .../Utils/RichTextWriter.cs | 85 ++++ .../Xml/TagMatchingHeuristics.cs | 439 ------------------ .../Ast/AstNode.cs | 7 +- .../Implementation/AbstractFreezable.cs | 19 + .../Project/Workbench/File/FileService.cs | 5 - .../SharpDevelop/Workbench/FileService.cs | 2 +- 30 files changed, 1169 insertions(+), 656 deletions(-) create mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentTextWriter.cs create mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlOptions.cs create mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlRichTextWriter.cs create mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextColorizer.cs create mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModel.cs create mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModelWriter.cs create mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/PlainRichTextWriter.cs create mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/RichTextWriter.cs delete mode 100644 src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs diff --git a/SharpDevelop.Tests.sln b/SharpDevelop.Tests.sln index efa2b430af..995378c656 100644 --- a/SharpDevelop.Tests.sln +++ b/SharpDevelop.Tests.sln @@ -1,10 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -# SharpDevelop 4.3 +# SharpDevelop 5.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpDevelop.BuildWorker35", "src\Main\ICSharpCode.SharpDevelop.BuildWorker35\ICSharpCode.SharpDevelop.BuildWorker35.csproj", "{B5F54272-49F0-40DB-845A-8D837875D3BA}" EndProject @@ -27,8 +25,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpDevelop", "src\Main\SharpDevelop\SharpDevelop.csproj", "{1152B71B-3C05-4598-B20D-823B5D40559E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{2A232EF1-EB95-41C6-B63A-C106E0C95D3C}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil", "src\Libraries\cecil\Mono.Cecil.csproj", "{D68133BD-1E63-496E-9EDE-4FBDBF77B486}" EndProject @@ -58,20 +54,14 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "src\Libraries\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj", "{984CC812-9470-4A13-AFF9-CC44068D666C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AddIns", "AddIns", "{39327899-ED91-4F7F-988C-4FE4E17C014D}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Version Control", "Version Control", "{F208FF4F-E5D8-41D5-A7C7-B463976F156E}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitAddIn", "src\AddIns\VersionControl\GitAddIn\GitAddIn.csproj", "{83F15BA7-8478-4664-81BB-A82F146D88B3}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SubversionAddIn", "src\AddIns\VersionControl\SubversionAddIn\SubversionAddIn.csproj", "{17F4D7E0-6933-4C2E-8714-FD7E98D625D5}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Language Bindings", "Language Bindings", "{E0646C25-36F2-4524-969F-FA621353AB94}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpBinding", "src\AddIns\BackendBindings\CSharpBinding\Project\CSharpBinding.csproj", "{1F1AC7CD-D154-45BB-8EAF-804CA8055F5A}" EndProject @@ -100,8 +90,6 @@ EndProject Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "VBBinding", "src\AddIns\BackendBindings\VBBinding\Project\VBBinding.vbproj", "{6D209CBB-D8C1-478A-BC30-D3FC87B7858F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{F3662720-9EA2-4591-BBC6-97361DCE50A9}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelpViewer", "src\AddIns\Misc\HelpViewer\HelpViewer.csproj", "{80F76D10-0B44-4D55-B4BD-DAEB5464090C}" EndProject @@ -116,8 +104,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegExpTk", "src\AddIns\Misc\RegExpTk\Project\RegExpTk.csproj", "{64A3E5E6-90BF-47F6-94DF-68C94B62C817}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UsageDataCollector", "UsageDataCollector", "{DEFC8584-BEC3-4921-BD0F-40482E450B7B}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UsageDataCollector", "src\AddIns\Misc\UsageDataCollector\UsageDataCollector\UsageDataCollector.csproj", "{6B1CFE35-DA17-4DEB-9C6E-227E5E251DA0}" EndProject @@ -130,8 +116,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TextTemplating", "src\AddIns\Misc\TextTemplating\Project\TextTemplating.csproj", "{B5D8C3E6-42EC-4D4B-AD05-3644B32563EF}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PackageManagement", "PackageManagement", "{485A4CCF-55CF-49F4-BD6D-A22B788C67DA}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PackageManagement", "src\AddIns\Misc\PackageManagement\Project\PackageManagement.csproj", "{AE4AB0FA-6087-4480-AF37-0FA1452B3DA1}" EndProject @@ -146,16 +130,12 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PackageManagement.Cmdlets.Tests", "src\AddIns\Misc\PackageManagement\Cmdlets\Test\PackageManagement.Cmdlets.Tests.csproj", "{11115C83-3DB1-431F-8B98-59040359238D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AddInManager2", "AddInManager2", "{1F88F080-AD7C-4B03-9895-20C26282429D}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AddInManager2", "src\AddIns\Misc\AddInManager2\Project\AddInManager2.csproj", "{60480C2F-F228-4D86-B98F-AF75A7DCEC34}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AddInManager2.Tests", "src\AddIns\Misc\AddInManager2\AddInManager2.Tests\AddInManager2.Tests.csproj", "{0D0CB6E5-1EAD-471F-96B9-BFF84057BCF5}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Reports", "Reports", "{FEDD3FD9-0480-43CC-913C-4E0876DDA852}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Reports.Addin", "src\AddIns\Misc\Reports\ICSharpCode.Reports.Addin\ICSharpCode.Reports.Addin.csproj", "{62033CC6-01CD-47A2-ADFD-188E9C524C0A}" EndProject @@ -168,8 +148,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Irony", "src\AddIns\Misc\Reports\Irony\Irony.csproj", "{47B2D204-C993-4489-8B83-6DA7321CFAE0}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Display Bindings", "Display Bindings", "{11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvalonEdit.AddIn", "src\AddIns\DisplayBindings\AvalonEdit.AddIn\AvalonEdit.AddIn.csproj", "{0162E499-42D0-409B-AA25-EED21F75336B}" EndProject @@ -184,8 +162,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpyAddIn", "src\AddIns\DisplayBindings\ILSpyAddIn\ILSpyAddIn.csproj", "{8AA421C8-D7AF-4957-9F43-5135328ACB24}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Data", "Data", "{0F5192F2-0744-4BA9-A074-6BE82D111B8D}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Data.Addin", "src\AddIns\DisplayBindings\Data\ICSharpCode.Data.Addin\ICSharpCode.Data.Addin.csproj", "{A9F12710-24E4-46D4-832C-6ECB395B9EAD}" EndProject @@ -200,8 +176,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Data.SQLServer", "src\AddIns\DisplayBindings\Data\ICSharpCode.Data.SQLServer\ICSharpCode.Data.SQLServer.csproj", "{AFE34868-AFA1-4E1C-9450-47AB4BE329D5}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WpfDesign", "WpfDesign", "{83BAB756-1010-4A2F-9B9D-7F9EBCB288F5}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfDesign", "src\AddIns\DisplayBindings\WpfDesign\WpfDesign\Project\WpfDesign.csproj", "{66A378A1-E9F4-4AD5-8946-D0EC06C2902F}" EndProject @@ -218,8 +192,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FormsDesigner", "src\AddIns\DisplayBindings\FormsDesigner\Project\FormsDesigner.csproj", "{9E951B9F-6AC2-4537-9D0B-0AE7C026D5A1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Debugger", "Debugger", "{AF5E0DC1-1FA0-4346-A436-0C817C68F7C1}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Debugger.Core", "src\AddIns\Debugger\Debugger.Core\Debugger.Core.csproj", "{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}" EndProject @@ -228,8 +200,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Debugger.Tests", "src\AddIns\Debugger\Debugger.Tests\Debugger.Tests.csproj", "{A4C858C8-51B6-4265-A695-A20FCEBA1D19}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analysis", "Analysis", "{B3352C08-3CB4-4DD9-996F-B9DCE4356BB9}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTesting", "src\AddIns\Analysis\UnitTesting\UnitTesting.csproj", "{1F261725-6318-4434-A1B1-6C70CE4CD324}" EndProject @@ -250,8 +220,6 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeQuality", "src\AddIns\Analysis\CodeQuality\CodeQuality.csproj", "{0A029008-4973-4256-9150-9AF12845C547}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Profiler", "Profiler", "{7D16E1F9-0F9F-4A05-A162-A59C05E88B68}" - ProjectSection(SolutionItems) = postProject - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Profiler.Tests", "src\AddIns\Analysis\Profiler\Tests\Profiler.Tests\Profiler.Tests.csproj", "{DAEA4E6C-02CD-47DA-806B-1FCE1E9675EC}" EndProject @@ -637,14 +605,6 @@ Global {0A029008-4973-4256-9150-9AF12845C547}.Debug|Any CPU.Build.0 = Debug|Any CPU {0A029008-4973-4256-9150-9AF12845C547}.Release|Any CPU.ActiveCfg = Release|Any CPU {0A029008-4973-4256-9150-9AF12845C547}.Release|Any CPU.Build.0 = Release|Any CPU - {E2FD63DA-8478-4066-934C-DA82A852C83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E2FD63DA-8478-4066-934C-DA82A852C83A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E2FD63DA-8478-4066-934C-DA82A852C83A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E2FD63DA-8478-4066-934C-DA82A852C83A}.Release|Any CPU.Build.0 = Release|Any CPU - {3DF4060F-5EE0-41CF-8096-F27355FD5511}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3DF4060F-5EE0-41CF-8096-F27355FD5511}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3DF4060F-5EE0-41CF-8096-F27355FD5511}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3DF4060F-5EE0-41CF-8096-F27355FD5511}.Release|Any CPU.Build.0 = Release|Any CPU {DAEA4E6C-02CD-47DA-806B-1FCE1E9675EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DAEA4E6C-02CD-47DA-806B-1FCE1E9675EC}.Debug|Any CPU.Build.0 = Debug|Any CPU {DAEA4E6C-02CD-47DA-806B-1FCE1E9675EC}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -665,6 +625,14 @@ Global {D7DB55CF-58F8-4164-A6C9-AE7456E5BEF3}.Debug|Any CPU.Build.0 = Debug|Any CPU {D7DB55CF-58F8-4164-A6C9-AE7456E5BEF3}.Release|Any CPU.ActiveCfg = Release|Any CPU {D7DB55CF-58F8-4164-A6C9-AE7456E5BEF3}.Release|Any CPU.Build.0 = Release|Any CPU + {E2FD63DA-8478-4066-934C-DA82A852C83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2FD63DA-8478-4066-934C-DA82A852C83A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2FD63DA-8478-4066-934C-DA82A852C83A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2FD63DA-8478-4066-934C-DA82A852C83A}.Release|Any CPU.Build.0 = Release|Any CPU + {3DF4060F-5EE0-41CF-8096-F27355FD5511}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3DF4060F-5EE0-41CF-8096-F27355FD5511}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3DF4060F-5EE0-41CF-8096-F27355FD5511}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3DF4060F-5EE0-41CF-8096-F27355FD5511}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -683,24 +651,19 @@ Global {D68133BD-1E63-496E-9EDE-4FBDBF77B486} = {2A232EF1-EB95-41C6-B63A-C106E0C95D3C} {6222A3A1-83CE-47A3-A4E4-A018F82D44D8} = {2A232EF1-EB95-41C6-B63A-C106E0C95D3C} {E5A0F4D8-37FD-4A30-BEB0-4409DC4E0865} = {2A232EF1-EB95-41C6-B63A-C106E0C95D3C} + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} = {E5A0F4D8-37FD-4A30-BEB0-4409DC4E0865} + {53DCA265-3C3C-42F9-B647-F72BA678122B} = {E5A0F4D8-37FD-4A30-BEB0-4409DC4E0865} + {DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6} = {E5A0F4D8-37FD-4A30-BEB0-4409DC4E0865} + {63D3B27A-D966-4902-90B3-30290E1692F1} = {E5A0F4D8-37FD-4A30-BEB0-4409DC4E0865} {2FF700C2-A38A-48BD-A637-8CAFD4FE6237} = {2A232EF1-EB95-41C6-B63A-C106E0C95D3C} {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1} = {2A232EF1-EB95-41C6-B63A-C106E0C95D3C} {4139CCF6-FB49-4A9D-B2CF-331E9EA3198D} = {2A232EF1-EB95-41C6-B63A-C106E0C95D3C} {DDE2A481-8271-4EAC-A330-8FA6A38D13D1} = {2A232EF1-EB95-41C6-B63A-C106E0C95D3C} {984CC812-9470-4A13-AFF9-CC44068D666C} = {2A232EF1-EB95-41C6-B63A-C106E0C95D3C} - {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} = {E5A0F4D8-37FD-4A30-BEB0-4409DC4E0865} - {53DCA265-3C3C-42F9-B647-F72BA678122B} = {E5A0F4D8-37FD-4A30-BEB0-4409DC4E0865} - {DC393B66-92ED-4CAD-AB25-CFEF23F3D7C6} = {E5A0F4D8-37FD-4A30-BEB0-4409DC4E0865} - {63D3B27A-D966-4902-90B3-30290E1692F1} = {E5A0F4D8-37FD-4A30-BEB0-4409DC4E0865} {F208FF4F-E5D8-41D5-A7C7-B463976F156E} = {39327899-ED91-4F7F-988C-4FE4E17C014D} - {E0646C25-36F2-4524-969F-FA621353AB94} = {39327899-ED91-4F7F-988C-4FE4E17C014D} - {F3662720-9EA2-4591-BBC6-97361DCE50A9} = {39327899-ED91-4F7F-988C-4FE4E17C014D} - {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} = {39327899-ED91-4F7F-988C-4FE4E17C014D} - {AF5E0DC1-1FA0-4346-A436-0C817C68F7C1} = {39327899-ED91-4F7F-988C-4FE4E17C014D} - {B3352C08-3CB4-4DD9-996F-B9DCE4356BB9} = {39327899-ED91-4F7F-988C-4FE4E17C014D} - {E2FD63DA-8478-4066-934C-DA82A852C83A} = {39327899-ED91-4F7F-988C-4FE4E17C014D} {83F15BA7-8478-4664-81BB-A82F146D88B3} = {F208FF4F-E5D8-41D5-A7C7-B463976F156E} {17F4D7E0-6933-4C2E-8714-FD7E98D625D5} = {F208FF4F-E5D8-41D5-A7C7-B463976F156E} + {E0646C25-36F2-4524-969F-FA621353AB94} = {39327899-ED91-4F7F-988C-4FE4E17C014D} {1F1AC7CD-D154-45BB-8EAF-804CA8055F5A} = {E0646C25-36F2-4524-969F-FA621353AB94} {E954F3CB-A446-492F-A664-2B376EBC86E8} = {E0646C25-36F2-4524-969F-FA621353AB94} {70966F84-74C9-4067-A379-0C674A929233} = {E0646C25-36F2-4524-969F-FA621353AB94} @@ -714,6 +677,7 @@ Global {85C09AD8-183B-403A-869A-7226646218A9} = {E0646C25-36F2-4524-969F-FA621353AB94} {CAD4D128-5A67-444B-88AE-37E0AF79C57E} = {E0646C25-36F2-4524-969F-FA621353AB94} {6D209CBB-D8C1-478A-BC30-D3FC87B7858F} = {E0646C25-36F2-4524-969F-FA621353AB94} + {F3662720-9EA2-4591-BBC6-97361DCE50A9} = {39327899-ED91-4F7F-988C-4FE4E17C014D} {80F76D10-0B44-4D55-B4BD-DAEB5464090C} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {9196DD8A-B4D4-4780-8742-C5762E547FC2} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {7D5C266F-D6FF-4D14-B315-0C0FC6C4EF51} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} @@ -721,27 +685,28 @@ Global {D022A6CE-7438-41E8-AC64-F2DE18EC54C6} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {64A3E5E6-90BF-47F6-94DF-68C94B62C817} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {DEFC8584-BEC3-4921-BD0F-40482E450B7B} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} + {6B1CFE35-DA17-4DEB-9C6E-227E5E251DA0} = {DEFC8584-BEC3-4921-BD0F-40482E450B7B} + {0008FCE9-9EB4-4E2E-979B-553278E5BBA6} = {DEFC8584-BEC3-4921-BD0F-40482E450B7B} {A569DCC1-C608-45FD-B770-4F79335EF154} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {5186325C-DD7F-4246-9BE7-3F384EFBF5A6} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {B5D8C3E6-42EC-4D4B-AD05-3644B32563EF} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {485A4CCF-55CF-49F4-BD6D-A22B788C67DA} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} - {1F88F080-AD7C-4B03-9895-20C26282429D} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} - {FEDD3FD9-0480-43CC-913C-4E0876DDA852} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} - {6B1CFE35-DA17-4DEB-9C6E-227E5E251DA0} = {DEFC8584-BEC3-4921-BD0F-40482E450B7B} - {0008FCE9-9EB4-4E2E-979B-553278E5BBA6} = {DEFC8584-BEC3-4921-BD0F-40482E450B7B} {AE4AB0FA-6087-4480-AF37-0FA1452B3DA1} = {485A4CCF-55CF-49F4-BD6D-A22B788C67DA} {A406803B-C584-43A3-BCEE-A0BB3132CB5F} = {485A4CCF-55CF-49F4-BD6D-A22B788C67DA} {C3F15E22-5793-4129-AF8C-6229112B86D2} = {485A4CCF-55CF-49F4-BD6D-A22B788C67DA} {56E98A01-8398-4A08-9578-C7337711A52B} = {485A4CCF-55CF-49F4-BD6D-A22B788C67DA} {E0A5E80A-003B-4335-A9DC-A76E2E46D38D} = {485A4CCF-55CF-49F4-BD6D-A22B788C67DA} {11115C83-3DB1-431F-8B98-59040359238D} = {485A4CCF-55CF-49F4-BD6D-A22B788C67DA} + {1F88F080-AD7C-4B03-9895-20C26282429D} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {60480C2F-F228-4D86-B98F-AF75A7DCEC34} = {1F88F080-AD7C-4B03-9895-20C26282429D} {0D0CB6E5-1EAD-471F-96B9-BFF84057BCF5} = {1F88F080-AD7C-4B03-9895-20C26282429D} + {FEDD3FD9-0480-43CC-913C-4E0876DDA852} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {62033CC6-01CD-47A2-ADFD-188E9C524C0A} = {FEDD3FD9-0480-43CC-913C-4E0876DDA852} {2EE63FDD-7F49-40BD-8A2E-240848B9FA83} = {FEDD3FD9-0480-43CC-913C-4E0876DDA852} {0884566C-E013-4185-B223-47547AA75167} = {FEDD3FD9-0480-43CC-913C-4E0876DDA852} {1491E558-9C19-4EAC-9406-868AB8181F38} = {FEDD3FD9-0480-43CC-913C-4E0876DDA852} {47B2D204-C993-4489-8B83-6DA7321CFAE0} = {FEDD3FD9-0480-43CC-913C-4E0876DDA852} + {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} = {39327899-ED91-4F7F-988C-4FE4E17C014D} {0162E499-42D0-409B-AA25-EED21F75336B} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {E618A9CD-A39F-4925-A538-E8A3FEF24E54} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {DCA2703D-250A-463E-A68A-07ED105AE6BD} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} @@ -749,23 +714,25 @@ Global {DFB936AD-90EE-4B4F-941E-4F4A636F0D92} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {8AA421C8-D7AF-4957-9F43-5135328ACB24} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {0F5192F2-0744-4BA9-A074-6BE82D111B8D} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} - {83BAB756-1010-4A2F-9B9D-7F9EBCB288F5} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} - {85226AFB-CE71-4851-9A75-7EEC663A8E8A} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} - {9E951B9F-6AC2-4537-9D0B-0AE7C026D5A1} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {A9F12710-24E4-46D4-832C-6ECB395B9EAD} = {0F5192F2-0744-4BA9-A074-6BE82D111B8D} {B7823AE9-4B43-4859-8796-2EBDC116FBB8} = {0F5192F2-0744-4BA9-A074-6BE82D111B8D} {BAD94D6E-4159-4CB6-B991-486F412D9BB6} = {0F5192F2-0744-4BA9-A074-6BE82D111B8D} {5C70D6AB-0A33-43F9-B8B5-54558C35BBB1} = {0F5192F2-0744-4BA9-A074-6BE82D111B8D} {EEF5E054-4192-4A57-8FBF-E860D808A51D} = {0F5192F2-0744-4BA9-A074-6BE82D111B8D} {AFE34868-AFA1-4E1C-9450-47AB4BE329D5} = {0F5192F2-0744-4BA9-A074-6BE82D111B8D} + {83BAB756-1010-4A2F-9B9D-7F9EBCB288F5} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {66A378A1-E9F4-4AD5-8946-D0EC06C2902F} = {83BAB756-1010-4A2F-9B9D-7F9EBCB288F5} {9A9D6FD4-6A2E-455D-ACC3-DDA775FE9865} = {83BAB756-1010-4A2F-9B9D-7F9EBCB288F5} {943DBBB3-E84E-4CF4-917C-C05AFA8743C1} = {83BAB756-1010-4A2F-9B9D-7F9EBCB288F5} {78CC29AC-CC79-4355-B1F2-97936DF198AC} = {83BAB756-1010-4A2F-9B9D-7F9EBCB288F5} {88DA149F-21B2-48AB-82C4-28FB6BDFD783} = {83BAB756-1010-4A2F-9B9D-7F9EBCB288F5} + {85226AFB-CE71-4851-9A75-7EEC663A8E8A} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} + {9E951B9F-6AC2-4537-9D0B-0AE7C026D5A1} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} + {AF5E0DC1-1FA0-4346-A436-0C817C68F7C1} = {39327899-ED91-4F7F-988C-4FE4E17C014D} {1D18D788-F7EE-4585-A23B-34DC8EC63CB8} = {AF5E0DC1-1FA0-4346-A436-0C817C68F7C1} {EC06F96A-AEEC-49D6-B03D-AB87C6EB674C} = {AF5E0DC1-1FA0-4346-A436-0C817C68F7C1} {A4C858C8-51B6-4265-A695-A20FCEBA1D19} = {AF5E0DC1-1FA0-4346-A436-0C817C68F7C1} + {B3352C08-3CB4-4DD9-996F-B9DCE4356BB9} = {39327899-ED91-4F7F-988C-4FE4E17C014D} {1F261725-6318-4434-A1B1-6C70CE4CD324} = {B3352C08-3CB4-4DD9-996F-B9DCE4356BB9} {44A8DE09-CAB9-49D8-9CFC-5EB0A552F181} = {B3352C08-3CB4-4DD9-996F-B9DCE4356BB9} {3EAA45A9-735C-4AC7-A799-947B93EA449D} = {B3352C08-3CB4-4DD9-996F-B9DCE4356BB9} @@ -781,5 +748,6 @@ Global {CEFF8221-95D8-4F60-9D14-687019D0B2E8} = {7D16E1F9-0F9F-4A05-A162-A59C05E88B68} {BD38E43B-947F-474B-8F6C-8BDAA9EE99A6} = {7D16E1F9-0F9F-4A05-A162-A59C05E88B68} {D7DB55CF-58F8-4164-A6C9-AE7456E5BEF3} = {7D16E1F9-0F9F-4A05-A162-A59C05E88B68} + {E2FD63DA-8478-4066-934C-DA82A852C83A} = {39327899-ED91-4F7F-988C-4FE4E17C014D} EndGlobalSection EndGlobal diff --git a/src/AddIns/Analysis/CodeQuality/Gui/Commands/AnalyzeCodeQualityCommand.cs b/src/AddIns/Analysis/CodeQuality/Gui/Commands/AnalyzeCodeQualityCommand.cs index 73771df9d2..679116ecb0 100644 --- a/src/AddIns/Analysis/CodeQuality/Gui/Commands/AnalyzeCodeQualityCommand.cs +++ b/src/AddIns/Analysis/CodeQuality/Gui/Commands/AnalyzeCodeQualityCommand.cs @@ -3,7 +3,7 @@ using System; using ICSharpCode.Core; -using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop; namespace ICSharpCode.CodeQuality.Gui { @@ -11,7 +11,7 @@ namespace ICSharpCode.CodeQuality.Gui { public override void Run() { - WorkbenchSingleton.Workbench.ShowView(new AnalyzeCodeQualityViewContent()); + SD.Workbench.ShowView(new AnalyzeCodeQualityViewContent()); } } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs index 9a7115b3ae..1638959b29 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/OverrideEqualsGetHashCodeMethodsDialog.xaml.cs @@ -320,7 +320,7 @@ namespace CSharpBinding.Refactoring method.Body.Add(new VariableDeclarationStatement( currentType.Clone(), "other", - new CastExpression(currentType.Clone(), new IdentifierExpression("obj")))); + new IdentifierExpression("obj").CastAs(currentType.Clone()))); method.Body.Add(new IfElseStatement( new BinaryOperatorExpression(new IdentifierExpression("other"), BinaryOperatorType.Equality, new PrimitiveExpression(null, "null")), new ReturnStatement(new PrimitiveExpression(false, "false")))); diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementWorkbench.cs b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementWorkbench.cs index d3332ae8de..f3581478f9 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementWorkbench.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/PackageManagementWorkbench.cs @@ -49,7 +49,7 @@ namespace ICSharpCode.PackageManagement public R SafeThreadFunction(Func method) { - return WorkbenchSingleton.SafeThreadFunction(method); + return SD.MainThread.InvokeIfRequired(method); } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs index e0c4566bc2..6f3786061b 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs @@ -25,9 +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 + - "    string " + - "text = SomeMethod();", html); + Assert.AreEqual("using System.Text;
" + Environment.NewLine + + "    string " + + "text = SomeMethod();", html); } [Test] diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CompressingTreeListTests.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CompressingTreeListTests.cs index afb78027b0..f60b9ce822 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CompressingTreeListTests.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CompressingTreeListTests.cs @@ -30,12 +30,7 @@ namespace ICSharpCode.AvalonEdit.Utils list.InsertRange(0, billion, "A"); list.InsertRange(1, billion, "B"); Assert.AreEqual(2 * billion, list.Count); - try { - list.InsertRange(2, billion, "C"); - Assert.Fail("Expected OverflowException"); - } catch (OverflowException) { - // expected - } + Assert.Throws(delegate { list.InsertRange(2, billion, "C"); }); } [Test] @@ -103,5 +98,34 @@ namespace ICSharpCode.AvalonEdit.Utils list.RemoveRange(0, 3); Assert.AreEqual(new[] { 2, 3, 3 }, list.ToArray()); } + + [Test] + public void Transform() + { + CompressingTreeList list = new CompressingTreeList((a, b) => a == b); + list.AddRange(new[] { 0, 1, 1, 0 }); + int calls = 0; + list.Transform(i => { calls++; return i + 1; }); + Assert.AreEqual(3, calls); + Assert.AreEqual(new[] { 1, 2, 2, 1 }, list.ToArray()); + } + + [Test] + public void TransformToZero() + { + CompressingTreeList list = new CompressingTreeList((a, b) => a == b); + list.AddRange(new[] { 0, 1, 1, 0 }); + list.Transform(i => 0); + Assert.AreEqual(new[] { 0, 0, 0, 0 }, list.ToArray()); + } + + [Test] + public void TransformRange() + { + CompressingTreeList list = new CompressingTreeList((a, b) => a == b); + list.AddRange(new[] { 0, 1, 1, 1, 0, 0 }); + list.TransformRange(2, 3, i => 0); + Assert.AreEqual(new[] { 0, 1, 0, 0, 0, 0 }, list.ToArray()); + } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentTextWriter.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentTextWriter.cs new file mode 100644 index 0000000000..be907a2792 --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentTextWriter.cs @@ -0,0 +1,69 @@ +// 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; +using System.IO; +using System.Text; +using ICSharpCode.NRefactory.Editor; + +namespace ICSharpCode.AvalonEdit.Document +{ + /// + /// A TextWriter implementation that directly inserts into a document. + /// + public class DocumentTextWriter : TextWriter + { + readonly IDocument document; + int insertionOffset; + + /// + /// Creates a new DocumentTextWriter that inserts into document, starting at insertionOffset. + /// + public DocumentTextWriter(IDocument document, int insertionOffset) + { + this.insertionOffset = insertionOffset; + if (document == null) + throw new ArgumentNullException("document"); + this.document = document; + var line = document.GetLineByOffset(insertionOffset); + if (line.DelimiterLength == 0) + line = line.PreviousLine; + if (line != null) + this.NewLine = document.GetText(line.EndOffset, line.DelimiterLength); + } + + /// + /// Gets/Sets the current insertion offset. + /// + public int InsertionOffset { + get { return insertionOffset; } + set { insertionOffset = value; } + } + + /// + public override void Write(char value) + { + document.Insert(insertionOffset, value.ToString()); + insertionOffset++; + } + + /// + public override void Write(char[] buffer, int index, int count) + { + document.Insert(insertionOffset, new string(buffer, index, count)); + insertionOffset += count; + } + + /// + public override void Write(string value) + { + document.Insert(insertionOffset, value); + insertionOffset += value.Length; + } + + /// + public override Encoding Encoding { + get { return Encoding.UTF8; } + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs index c26f112995..69abb830a9 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs @@ -117,9 +117,9 @@ namespace ICSharpCode.AvalonEdit.Document /// /// Gets the newline sequence used in the document at the specified line. /// - public static string GetNewLineFromDocument(TextDocument document, int lineNumber) + public static string GetNewLineFromDocument(IDocument document, int lineNumber) { - DocumentLine line = document.GetLineByNumber(lineNumber); + IDocumentLine line = document.GetLineByNumber(lineNumber); if (line.DelimiterLength == 0) { // at the end of the document, there's no line delimiter, so use the delimiter // from the previous line diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocumentWeakEventManager.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocumentWeakEventManager.cs index ba71084cbc..e4ad83fb08 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocumentWeakEventManager.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocumentWeakEventManager.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using ICSharpCode.NRefactory.Editor; using ICSharpCode.AvalonEdit.Utils; namespace ICSharpCode.AvalonEdit.Document diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs index 2d324173fa..61704f83fc 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedInlineBuilder.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Text; using System.Windows; using System.Windows.Documents; using System.Windows.Media; @@ -73,11 +74,11 @@ namespace ICSharpCode.AvalonEdit.Highlighting stateChanges.Add(new HighlightingState()); } - HighlightedInlineBuilder(string text, int[] offsets, HighlightingState[] states) + HighlightedInlineBuilder(string text, List offsets, List states) { this.text = text; - stateChangeOffsets.AddRange(offsets); - stateChanges.AddRange(states); + stateChangeOffsets = offsets; + stateChanges = states; } /// @@ -207,8 +208,8 @@ namespace ICSharpCode.AvalonEdit.Highlighting public HighlightedInlineBuilder Clone() { return new HighlightedInlineBuilder(this.text, - stateChangeOffsets.ToArray(), - stateChanges.Select(sc => sc.Clone()).ToArray()); + stateChangeOffsets.ToList(), + stateChanges.Select(sc => sc.Clone()).ToList()); } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs index 35768891a7..4733f3c4ae 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightedLine.cs @@ -167,7 +167,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting } #endregion - #region ToHtml + #region WriteTo / ToHtml sealed class HtmlElement : IComparable { internal readonly int Offset; @@ -203,21 +203,21 @@ namespace ICSharpCode.AvalonEdit.Highlighting } /// - /// Produces HTML code for the line, with <span class="colorName"> tags. + /// Writes the highlighted line to the RichTextWriter. /// - public string ToHtml(HtmlOptions options) + public void WriteTo(RichTextWriter writer) { int startOffset = this.DocumentLine.Offset; - return ToHtml(startOffset, startOffset + this.DocumentLine.Length, options); + WriteTo(writer, startOffset, startOffset + this.DocumentLine.Length); } /// - /// Produces HTML code for a section of the line, with <span class="colorName"> tags. + /// Writes a part of the highlighted line to the RichTextWriter. /// - public string ToHtml(int startOffset, int endOffset, HtmlOptions options) + public void WriteTo(RichTextWriter writer, int startOffset, int endOffset) { - if (options == null) - throw new ArgumentNullException("options"); + if (writer == null) + throw new ArgumentNullException("writer"); int documentLineStartOffset = this.DocumentLine.Offset; int documentLineEndOffset = documentLineStartOffset + this.DocumentLine.Length; if (startOffset < documentLineStartOffset || startOffset > documentLineEndOffset) @@ -237,32 +237,49 @@ namespace ICSharpCode.AvalonEdit.Highlighting elements.Sort(); IDocument document = this.Document; - StringWriter w = new StringWriter(CultureInfo.InvariantCulture); int textOffset = startOffset; foreach (HtmlElement e in elements) { int newOffset = Math.Min(e.Offset, endOffset); if (newOffset > startOffset) { - HtmlClipboard.EscapeHtml(w, document.GetText(textOffset, newOffset - textOffset), options); + document.WriteTextTo(writer, textOffset, newOffset - textOffset); } textOffset = Math.Max(textOffset, newOffset); - if (options.ColorNeedsSpanForStyling(e.Color)) { - if (e.IsEnd) { - w.Write(""); - } else { - w.Write("'); - } - } + if (e.IsEnd) + writer.EndSpan(); + else + writer.BeginSpan(e.Color); + } + document.WriteTextTo(writer, textOffset, endOffset - textOffset); + } + + /// + /// Produces HTML code for the line, with <span class="colorName"> tags. + /// + public string ToHtml(HtmlOptions options = null) + { + StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); + using (var htmlWriter = new HtmlRichTextWriter(stringWriter, options)) { + WriteTo(htmlWriter); + } + return stringWriter.ToString(); + } + + /// + /// Produces HTML code for a section of the line, with <span class="colorName"> tags. + /// + public string ToHtml(int startOffset, int endOffset, HtmlOptions options = null) + { + StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); + using (var htmlWriter = new HtmlRichTextWriter(stringWriter, options)) { + WriteTo(htmlWriter, startOffset, endOffset); } - HtmlClipboard.EscapeHtml(w, document.GetText(textOffset, endOffset - textOffset), options); - return w.ToString(); + return stringWriter.ToString(); } /// public override string ToString() { - return "[" + GetType().Name + " " + ToHtml(new HtmlOptions()) + "]"; + return "[" + GetType().Name + " " + ToHtml() + "]"; } #endregion diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs index 2542062387..919de53dce 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingBrush.cs @@ -75,6 +75,19 @@ namespace ICSharpCode.AvalonEdit.Highlighting { info.AddValue("color", brush.Color.ToString(CultureInfo.InvariantCulture)); } + + public override bool Equals(object obj) + { + SimpleHighlightingBrush other = obj as SimpleHighlightingBrush; + if (other == null) + return false; + return this.brush.Color.Equals(other.brush.Color); + } + + public override int GetHashCode() + { + return brush.Color.GetHashCode(); + } } /// @@ -113,5 +126,18 @@ namespace ICSharpCode.AvalonEdit.Highlighting { info.AddValue("propertyName", property.Name); } + + public override bool Equals(object obj) + { + SystemColorHighlightingBrush other = obj as SystemColorHighlightingBrush; + if (other == null) + return false; + return object.Equals(this.property, other.property); + } + + public override int GetHashCode() + { + return property.GetHashCode(); + } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColor.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColor.cs index 66cbb2869c..6632b93603 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColor.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColor.cs @@ -8,6 +8,8 @@ using System.Security.Permissions; using System.Text; using System.Windows; using System.Windows.Media; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; namespace ICSharpCode.AvalonEdit.Highlighting { @@ -15,8 +17,10 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// A highlighting color is a set of font properties and foreground and background color. /// [Serializable] - public class HighlightingColor : ISerializable + public class HighlightingColor : ISerializable, IFreezable, ICloneable, IEquatable { + internal static readonly HighlightingColor Empty = FreezableHelper.FreezeAndReturn(new HighlightingColor()); + string name; FontWeight? fontWeight; FontStyle? fontStyle; @@ -175,7 +179,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// /// Prevent further changes to this highlighting color. /// - public void Freeze() + public virtual void Freeze() { frozen = true; } @@ -186,5 +190,69 @@ namespace ICSharpCode.AvalonEdit.Highlighting public bool IsFrozen { get { return frozen; } } + + /// + /// Clones this highlighting color. + /// If this color is frozen, the clone will be unfrozen. + /// + public virtual HighlightingColor Clone() + { + HighlightingColor c = (HighlightingColor)MemberwiseClone(); + c.frozen = false; + return c; + } + + object ICloneable.Clone() + { + return Clone(); + } + + /// + public override sealed bool Equals(object obj) + { + return Equals(obj as HighlightingColor); + } + + /// + public virtual bool Equals(HighlightingColor other) + { + if (other == null) + return false; + return this.name == other.name && this.fontWeight == other.fontWeight && this.fontStyle == other.fontStyle && object.Equals(this.foreground, other.foreground) && object.Equals(this.background, other.background); + } + + /// + public override int GetHashCode() + { + int hashCode = 0; + unchecked { + if (name != null) + hashCode += 1000000007 * name.GetHashCode(); + hashCode += 1000000009 * fontWeight.GetHashCode(); + hashCode += 1000000021 * fontStyle.GetHashCode(); + if (foreground != null) + hashCode += 1000000033 * foreground.GetHashCode(); + if (background != null) + hashCode += 1000000087 * background.GetHashCode(); + } + return hashCode; + } + + /// + /// Overwrites the properties in this HighlightingColor with those from the given color; + /// but maintains the current values where the properties of the given color return null. + /// + public void MergeWith(HighlightingColor color) + { + FreezableHelper.ThrowIfFrozen(this); + if (color.fontWeight != null) + this.fontWeight = color.fontWeight; + if (color.fontStyle != null) + this.fontStyle = color.fontStyle; + if (color.foreground != null) + this.foreground = color.foreground; + if (color.background != null) + this.background = color.background; + } } } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs index ebc9e24f36..938108bb06 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs @@ -211,7 +211,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// 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) + internal static bool IsEmptyColor(HighlightingColor color) { if (color == null) return true; @@ -223,14 +223,19 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// Applies a highlighting color to a visual line element. /// protected virtual void ApplyColorToElement(VisualLineElement element, HighlightingColor color) + { + ApplyColorToElement(element, color, CurrentContext); + } + + internal static void ApplyColorToElement(VisualLineElement element, HighlightingColor color, ITextRunConstructionContext context) { if (color.Foreground != null) { - Brush b = color.Foreground.GetBrush(CurrentContext); + Brush b = color.Foreground.GetBrush(context); if (b != null) element.TextRunProperties.SetForegroundBrush(b); } if (color.Background != null) { - Brush b = color.Background.GetBrush(CurrentContext); + Brush b = color.Background.GetBrush(context); if (b != null) element.BackgroundBrush = b; } diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlClipboard.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlClipboard.cs index f8bc3e924d..4a5717c960 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlClipboard.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlClipboard.cs @@ -94,108 +94,5 @@ namespace ICSharpCode.AvalonEdit.Highlighting } return html.ToString(); } - - /// - /// Escapes text and writes the result to the StringBuilder. - /// - internal static void EscapeHtml(StringWriter w, string text, HtmlOptions options) - { - int spaceCount = -1; - foreach (char c in text) { - if (c == ' ') { - if (spaceCount < 0) - w.Write(" "); - else - spaceCount++; - } else if (c == '\t') { - if (spaceCount < 0) - spaceCount = 0; - spaceCount += options.TabSize; - } else { - if (spaceCount == 1) { - w.Write(' '); - } else if (spaceCount >= 1) { - for (int i = 0; i < spaceCount; i++) { - w.Write(" "); - } - } - spaceCount = 0; - switch (c) { - case '<': - w.Write("<"); - break; - case '>': - w.Write(">"); - break; - case '&': - w.Write("&"); - break; - case '"': - w.Write("""); - break; - default: - w.Write(c); - break; - } - } - } - for (int i = 0; i < spaceCount; i++) { - w.Write(" "); - } - } - } - - /// - /// Holds options for converting text to HTML. - /// - public class HtmlOptions - { - /// - /// Creates a default HtmlOptions instance. - /// - public HtmlOptions() - { - this.TabSize = 4; - } - - /// - /// Creates a new HtmlOptions instance that copies applicable options from the . - /// - public HtmlOptions(TextEditorOptions options) - : this() - { - if (options == null) - throw new ArgumentNullException("options"); - this.TabSize = options.IndentationSize; - } - - /// - /// The amount of spaces a tab gets converted to. - /// - public int TabSize { get; set; } - - /// - /// Writes the HTML attribute for the style to the text writer. - /// - public virtual void WriteStyleAttributeForColor(TextWriter writer, HighlightingColor color) - { - if (writer == null) - throw new ArgumentNullException("writer"); - if (color == null) - throw new ArgumentNullException("color"); - writer.Write(" style=\""); - 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/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlOptions.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlOptions.cs new file mode 100644 index 0000000000..a0fc28bc24 --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlOptions.cs @@ -0,0 +1,62 @@ +// 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; +using System.IO; +using System.Net; + +namespace ICSharpCode.AvalonEdit.Highlighting +{ + /// + /// Holds options for converting text to HTML. + /// + public class HtmlOptions + { + /// + /// Creates a default HtmlOptions instance. + /// + public HtmlOptions() + { + this.TabSize = 4; + } + + /// + /// Creates a new HtmlOptions instance that copies applicable options from the . + /// + public HtmlOptions(TextEditorOptions options) : this() + { + if (options == null) + throw new ArgumentNullException("options"); + this.TabSize = options.IndentationSize; + } + + /// + /// The amount of spaces a tab gets converted to. + /// + public int TabSize { get; set; } + + /// + /// Writes the HTML attribute for the style to the text writer. + /// + public virtual void WriteStyleAttributeForColor(TextWriter writer, HighlightingColor color) + { + if (writer == null) + throw new ArgumentNullException("writer"); + if (color == null) + throw new ArgumentNullException("color"); + writer.Write(" style=\""); + WebUtility.HtmlEncode(color.ToCss(), writer); + 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/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlRichTextWriter.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlRichTextWriter.cs new file mode 100644 index 0000000000..1c2a48d036 --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HtmlRichTextWriter.cs @@ -0,0 +1,236 @@ +// 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; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using System.Windows; +using System.Windows.Media; +using ICSharpCode.AvalonEdit.Utils; + +namespace ICSharpCode.AvalonEdit.Highlighting +{ + /// + /// RichTextWriter implementation that produces HTML. + /// + public class HtmlRichTextWriter : RichTextWriter + { + readonly TextWriter htmlWriter; + readonly HtmlOptions options; + Stack endTagStack = new Stack(); + bool spaceNeedsEscaping = true; + bool hasSpace; + bool needIndentation = true; + int indentationLevel; + + /// + /// Creates a new HtmlRichTextWriter instance. + /// + /// + /// The text writer where the raw HTML is written to. + /// The HtmlRichTextWriter does not take ownership of the htmlWriter; + /// disposing the HtmlRichTextWriter will not dispose the underlying htmlWriter! + /// + /// Options that control the HTML output. + public HtmlRichTextWriter(TextWriter htmlWriter, HtmlOptions options = null) + { + if (htmlWriter == null) + throw new ArgumentNullException("htmlWriter"); + this.htmlWriter = htmlWriter; + this.options = options ?? new HtmlOptions(); + } + + /// + public override Encoding Encoding { + get { return htmlWriter.Encoding; } + } + + /// + public override void Flush() + { + FlushSpace(true); // next char potentially might be whitespace + htmlWriter.Flush(); + } + + /// + protected override void Dispose(bool disposing) + { + if (disposing) { + FlushSpace(true); + } + base.Dispose(disposing); + } + + void FlushSpace(bool nextIsWhitespace) + { + if (hasSpace) { + if (spaceNeedsEscaping || nextIsWhitespace) + htmlWriter.Write(" "); + else + htmlWriter.Write(' '); + hasSpace = false; + spaceNeedsEscaping = true; + } + } + + void WriteIndentation() + { + if (needIndentation) { + for (int i = 0; i < indentationLevel; i++) { + WriteChar('\t'); + } + needIndentation = false; + } + } + + /// + public override void Write(char value) + { + WriteIndentation(); + WriteChar(value); + } + + static readonly char[] specialChars = { ' ', '\t', '\r', '\n' }; + + void WriteChar(char c) + { + bool isWhitespace = char.IsWhiteSpace(c); + FlushSpace(isWhitespace); + switch (c) { + case ' ': + if (spaceNeedsEscaping) + htmlWriter.Write(" "); + else + hasSpace = true; + break; + case '\t': + for (int i = 0; i < options.TabSize; i++) { + htmlWriter.Write(" "); + } + break; + case '\r': + break; // ignore; we'll write the
with the following \n + case '\n': + htmlWriter.Write("
"); + needIndentation = true; + break; + default: + WebUtility.HtmlEncode(c.ToString(), htmlWriter); + break; + } + // If we just handled a space by setting hasSpace = true, + // we mustn't set spaceNeedsEscaping as doing so would affect our own space, + // not just the following spaces. + if (c != ' ') { + // Following spaces must be escaped if c was a newline/tab; + // and they don't need escaping if c was a normal character. + spaceNeedsEscaping = isWhitespace; + } + } + + /// + public override void Write(string value) + { + int pos = 0; + do { + int endPos = value.IndexOfAny(specialChars, pos); + if (endPos < 0) { + WriteSimpleString(value.Substring(pos)); + return; // reached end of string + } + if (endPos > pos) + WriteSimpleString(value.Substring(pos, endPos - pos)); + WriteChar(value[pos]); + pos = endPos + 1; + } while (pos < value.Length); + } + + void WriteIndentationAndSpace() + { + WriteIndentation(); + FlushSpace(false); + } + + void WriteSimpleString(string value) + { + if (value.Length == 0) + return; + WriteIndentationAndSpace(); + WebUtility.HtmlEncode(value, htmlWriter); + } + + /// + public override void Indent() + { + indentationLevel++; + } + + /// + public override void Unindent() + { + if (indentationLevel == 0) + throw new NotSupportedException(); + indentationLevel--; + } + + /// + protected override void BeginUnhandledSpan() + { + endTagStack.Push(null); + } + + /// + public override void EndSpan() + { + htmlWriter.Write(endTagStack.Pop()); + } + + /// + public override void BeginSpan(Color foregroundColor) + { + BeginSpan(new HighlightingColor { Foreground = new SimpleHighlightingBrush(foregroundColor) }); + } + + /// + public override void BeginSpan(FontFamily fontFamily) + { + BeginUnhandledSpan(); // TODO + } + + /// + public override void BeginSpan(FontStyle fontStyle) + { + BeginSpan(new HighlightingColor { FontStyle = fontStyle }); + } + + /// + public override void BeginSpan(FontWeight fontWeight) + { + BeginSpan(new HighlightingColor { FontWeight = fontWeight }); + } + + /// + public override void BeginSpan(HighlightingColor highlightingColor) + { + WriteIndentationAndSpace(); + if (options.ColorNeedsSpanForStyling(highlightingColor)) { + htmlWriter.Write("'); + endTagStack.Push(""); + } else { + endTagStack.Push(null); + } + } + + /// + public override void BeginHyperlinkSpan(Uri uri) + { + WriteIndentationAndSpace(); + htmlWriter.Write(""); + endTagStack.Push(""); + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextColorizer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextColorizer.cs new file mode 100644 index 0000000000..1ffa7b24ec --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextColorizer.cs @@ -0,0 +1,39 @@ +// 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; +using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Rendering; + +namespace ICSharpCode.AvalonEdit.Highlighting +{ + /// + /// A colorizer that applies the highlighting from a to the editor. + /// + public class RichTextColorizer : DocumentColorizingTransformer + { + readonly RichTextModel richTextModel; + + /// + /// Creates a new RichTextColorizer instance. + /// + public RichTextColorizer(RichTextModel richTextModel) + { + if (richTextModel == null) + throw new ArgumentNullException("richTextModel"); + this.richTextModel = richTextModel; + } + + /// + protected override void ColorizeLine(DocumentLine line) + { + var sections = richTextModel.GetHighlightedSections(line.Offset, line.Length); + foreach (HighlightedSection section in sections) { + if (HighlightingColorizer.IsEmptyColor(section.Color)) + continue; + ChangeLinePart(section.Offset, section.Offset + section.Length, + visualLineElement => HighlightingColorizer.ApplyColorToElement(visualLineElement, section.Color, CurrentContext)); + } + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModel.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModel.cs new file mode 100644 index 0000000000..e808a4df2c --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModel.cs @@ -0,0 +1,165 @@ +// 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; +using System.Collections; +using System.Collections.Generic; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.TypeSystem.Implementation; +using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Utils; + +namespace ICSharpCode.AvalonEdit.Highlighting +{ + /// + /// Stores rich-text formatting. + /// + public sealed class RichTextModel + { + CompressingTreeList list = new CompressingTreeList(object.Equals); + + /// + /// Gets the length of the document. + /// This has an effect on which coordinates are valid for this RichTextModel. + /// + public int DocumentLength { + get { return list.Count; } + } + + /// + /// Creates a new RichTextModel that needs manual calls to . + /// + public RichTextModel(int documentLength) + { + list.InsertRange(0, documentLength, HighlightingColor.Empty); + } + + #region UpdateOffsets + /// + /// Updates the start and end offsets of all segments stored in this collection. + /// + /// DocumentChangeEventArgs instance describing the change to the document. + public void UpdateOffsets(DocumentChangeEventArgs e) + { + if (e == null) + throw new ArgumentNullException("e"); + OffsetChangeMap map = e.OffsetChangeMapOrNull; + if (map != null) { + foreach (OffsetChangeMapEntry entry in map) { + UpdateOffsetsInternal(entry); + } + } else { + UpdateOffsetsInternal(e.CreateSingleChangeMapEntry()); + } + } + + /// + /// Updates the start and end offsets of all segments stored in this collection. + /// + /// OffsetChangeMapEntry instance describing the change to the document. + public void UpdateOffsets(OffsetChangeMapEntry change) + { + UpdateOffsetsInternal(change); + } + + void UpdateOffsetsInternal(OffsetChangeMapEntry entry) + { + HighlightingColor color; + if (entry.RemovalLength > 0) { + color = list[entry.Offset]; + list.RemoveRange(entry.Offset, entry.RemovalLength); + } else if (list.Count > 0) { + color = list[Math.Max(0, entry.Offset - 1)]; + } else { + color = HighlightingColor.Empty; + } + list.InsertRange(entry.Offset, entry.InsertionLength, color); + } + #endregion + + /// + /// Gets the HighlightingColor for the specified offset. + /// + public HighlightingColor GetHighlighting(int offset) + { + return list[offset]; + } + + /// + /// Applies the HighlightingColor to the specified range of text. + /// If the color specifies null for some properties, existing highlighting is preserved. + /// + public void ApplyHighlighting(int offset, int length, HighlightingColor color) + { + list.TransformRange(offset, length, c => { + var newColor = c.Clone(); + newColor.MergeWith(color); + newColor.Freeze(); + return newColor; + }); + } + + /// + /// Sets the HighlightingColor for the specified range of text, + /// completely replacing the existing highlighting in that area. + /// + public void SetHighlighting(int offset, int length, HighlightingColor color) + { + list.SetRange(offset, length, FreezableHelper.GetFrozenClone(color)); + } + + /// + /// Retrieves the highlighted sections in the specified range. + /// The highlighted sections will be sorted by offset, and there will not be any nested or overlapping sections. + /// + public IEnumerable GetHighlightedSections(int offset, int length) + { + int pos = offset; + int endOffset = offset + length; + while (pos < endOffset) { + int endPos = Math.Min(endOffset, list.GetEndOfRun(pos)); + yield return new HighlightedSection { + Offset = pos, + Length = endPos - pos, + Color = list[pos] + }; + pos = endPos; + } + } + + #region WriteDocumentTo + /// + /// Writes the specified document, with the formatting from this rich text model applied, + /// to the RichTextWriter. + /// + public void WriteDocumentTo(ITextSource document, RichTextWriter writer) + { + WriteDocumentTo(document, new SimpleSegment(0, DocumentLength), writer); + } + + /// + /// Writes a segment of the specified document, with the formatting from this rich text model applied, + /// to the RichTextWriter. + /// + public void WriteDocumentTo(ITextSource document, ISegment segment, RichTextWriter writer) + { + if (document == null) + throw new ArgumentNullException("document"); + if (segment == null) + throw new ArgumentNullException("segment"); + if (writer == null) + throw new ArgumentNullException("writer"); + + int pos = segment.Offset; + int endOffset = segment.EndOffset; + while (pos < endOffset) { + int endPos = Math.Min(endOffset, list.GetEndOfRun(pos)); + writer.BeginSpan(list[pos]); + document.WriteTextTo(writer, pos, endPos - pos); + writer.EndSpan(); + pos = endPos; + } + } + #endregion + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModelWriter.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModelWriter.cs new file mode 100644 index 0000000000..39c1afa65b --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModelWriter.cs @@ -0,0 +1,118 @@ +// 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Windows; +using System.Windows.Media; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.AvalonEdit.Utils; + +namespace ICSharpCode.AvalonEdit.Highlighting +{ + /// + /// A RichTextWriter that writes into a document and . + /// + public class RichTextModelWriter : PlainRichTextWriter + { + readonly RichTextModel richTextModel; + readonly DocumentTextWriter documentTextWriter; + readonly Stack colorStack = new Stack(); + HighlightingColor currentColor; + int currentColorBegin = -1; + + /// + /// Creates a new RichTextModelWriter that inserts into document, starting at insertionOffset. + /// + public RichTextModelWriter(RichTextModel richTextModel, IDocument document, int insertionOffset) + : base(new DocumentTextWriter(document, insertionOffset)) + { + if (richTextModel == null) + throw new ArgumentNullException("richTextModel"); + this.richTextModel = richTextModel; + this.documentTextWriter = (DocumentTextWriter)base.textWriter; + if (richTextModel.DocumentLength == 0) + currentColor = HighlightingColor.Empty; + else + currentColor = richTextModel.GetHighlighting(Math.Max(0, insertionOffset - 1)); + } + + /// + /// Gets/Sets the current insertion offset. + /// + public int InsertionOffset { + get { return documentTextWriter.InsertionOffset; } + set { documentTextWriter.InsertionOffset = value; } + } + + + /// + protected override void BeginUnhandledSpan() + { + colorStack.Push(currentColor); + } + + void BeginColorSpan() + { + WriteIndentationIfNecessary(); + colorStack.Push(currentColor); + currentColor = currentColor.Clone(); + currentColorBegin = documentTextWriter.InsertionOffset; + } + + /// + public override void EndSpan() + { + currentColor = colorStack.Pop(); + currentColorBegin = documentTextWriter.InsertionOffset; + } + + /// + protected override void AfterWrite() + { + base.AfterWrite(); + richTextModel.SetHighlighting(currentColorBegin, documentTextWriter.InsertionOffset - currentColorBegin, currentColor); + } + + /// + public override void BeginSpan(Color foregroundColor) + { + BeginColorSpan(); + currentColor.Foreground = new SimpleHighlightingBrush(foregroundColor); + currentColor.Freeze(); + } + + /// + public override void BeginSpan(FontFamily fontFamily) + { + BeginUnhandledSpan(); // TODO + } + + /// + public override void BeginSpan(FontStyle fontStyle) + { + BeginColorSpan(); + currentColor.FontStyle = fontStyle; + currentColor.Freeze(); + } + + /// + public override void BeginSpan(FontWeight fontWeight) + { + BeginColorSpan(); + currentColor.FontWeight = fontWeight; + currentColor.Freeze(); + } + + /// + public override void BeginSpan(HighlightingColor highlightingColor) + { + BeginColorSpan(); + currentColor.MergeWith(highlightingColor); + currentColor.Freeze(); + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj index e95c47b1ae..9404abc687 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/ICSharpCode.AvalonEdit.csproj @@ -102,6 +102,7 @@ UndoStack.cs + @@ -196,6 +197,8 @@ + + @@ -204,6 +207,9 @@ + + + @@ -354,7 +360,9 @@ + + diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.cs index 98ab0b42d2..c25057eeac 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Search/SearchPanel.cs @@ -198,6 +198,7 @@ namespace ICSharpCode.AvalonEdit.Search { if (textArea == null) throw new ArgumentNullException("textArea"); + #pragma warning disable 618 SearchPanel panel = new SearchPanel(); panel.AttachInternal(textArea); panel.handler = new SearchInputHandler(textArea, panel); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs index 0ba831cc0a..0c9b77de09 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/CompressingTreeList.cs @@ -1,6 +1,6 @@ // 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) - +#define DATACONSISTENCYTEST using System; using System.Collections.Generic; using System.Diagnostics; @@ -411,8 +411,26 @@ namespace ICSharpCode.AvalonEdit.Utils } prevNode = n; } + CheckProperties(); + } + + /// + /// Applies the conversion function to the elements in the specified range. + /// + public void TransformRange(int index, int length, Func converter) + { + if (root == null) + return; + int endIndex = index + length; + int pos = index; + while (pos < endIndex) { + int endPos = Math.Min(endIndex, GetEndOfRun(pos)); + T oldValue = this[pos]; + T newValue = converter(oldValue); + SetRange(pos, endPos - pos, newValue); + pos = endPos; + } } - /// /// Inserts the specified at diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/PlainRichTextWriter.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/PlainRichTextWriter.cs new file mode 100644 index 0000000000..3a43e41cde --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/PlainRichTextWriter.cs @@ -0,0 +1,125 @@ +// 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; +using System.IO; +using System.Text; + +namespace ICSharpCode.AvalonEdit.Utils +{ + /// + /// RichTextWriter implementation that writes plain text only + /// and ignores all formatted spans. + /// + public class PlainRichTextWriter : RichTextWriter + { + /// + /// The text writer that was passed to the PlainRichTextWriter constructor. + /// + protected readonly TextWriter textWriter; + string indentationString = "\t"; + int indentationLevel; + char prevChar; + + /// + /// Creates a new PlainRichTextWriter instance that writes the text to the specified text writer. + /// + public PlainRichTextWriter(TextWriter textWriter) + { + if (textWriter == null) + throw new ArgumentNullException("textWriter"); + this.textWriter = textWriter; + } + + /// + /// Gets/Sets the string used to indent by one level. + /// + public string IndentationString { + get { + return indentationString; + } + set { + indentationString = value; + } + } + + /// + protected override void BeginUnhandledSpan() + { + } + + /// + public override void EndSpan() + { + } + + void WriteIndentation() + { + for (int i = 0; i < indentationLevel; i++) { + textWriter.Write(indentationString); + } + } + + /// + /// Writes the indentation, if necessary. + /// + protected void WriteIndentationIfNecessary() + { + if (prevChar == '\n') { + WriteIndentation(); + prevChar = '\0'; + } + } + + /// + /// Is called after a write operation. + /// + protected virtual void AfterWrite() + { + } + + /// + public override void Write(char value) + { + if (prevChar == '\n') + WriteIndentation(); + textWriter.Write(value); + prevChar = value; + AfterWrite(); + } + + /// + public override void Indent() + { + indentationLevel++; + } + + /// + public override void Unindent() + { + if (indentationLevel == 0) + throw new NotSupportedException(); + indentationLevel--; + } + + /// + public override Encoding Encoding { + get { return textWriter.Encoding; } + } + + /// + public override IFormatProvider FormatProvider { + get { return textWriter.FormatProvider; } + } + + /// + public override string NewLine { + get { + return textWriter.NewLine; + } + set { + textWriter.NewLine = value; + } + } + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/RichTextWriter.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/RichTextWriter.cs new file mode 100644 index 0000000000..ef274b4d14 --- /dev/null +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/RichTextWriter.cs @@ -0,0 +1,85 @@ +// 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; +using System.IO; +using System.Windows; +using System.Windows.Media; + +namespace ICSharpCode.AvalonEdit.Utils +{ + /// + /// A text writer that supports creating spans of highlighted text. + /// + public abstract class RichTextWriter : TextWriter + { + /// + /// Gets called by the RichTextWriter base class when a BeginSpan() method + /// that is not overwritten gets called. + /// + protected abstract void BeginUnhandledSpan(); + + /// + /// Begin a colored span. + /// + public virtual void BeginSpan(Color foregroundColor) + { + BeginUnhandledSpan(); + } + + /// + /// Begin a span with modified font weight. + /// + public virtual void BeginSpan(FontWeight fontWeight) + { + BeginUnhandledSpan(); + } + + /// + /// Begin a span with modified font style. + /// + public virtual void BeginSpan(FontStyle fontStyle) + { + BeginUnhandledSpan(); + } + + /// + /// Begin a span with modified font family. + /// + public virtual void BeginSpan(FontFamily fontFamily) + { + BeginUnhandledSpan(); + } + + /// + /// Begin a highlighted span. + /// + public virtual void BeginSpan(Highlighting.HighlightingColor highlightingColor) + { + BeginUnhandledSpan(); + } + + /// + /// Begin a span that links to the specified URI. + /// + public virtual void BeginHyperlinkSpan(Uri uri) + { + BeginUnhandledSpan(); + } + + /// + /// Marks the end of the current span. + /// + public abstract void EndSpan(); + + /// + /// Increases the indentation level. + /// + public abstract void Indent(); + + /// + /// Decreases the indentation level. + /// + public abstract void Unindent(); + } +} diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs deleted file mode 100644 index 6b5fd36b67..0000000000 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Xml/TagMatchingHeuristics.cs +++ /dev/null @@ -1,439 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using ICSharpCode.AvalonEdit.Utils; -using ICSharpCode.NRefactory.Utils; - -namespace ICSharpCode.AvalonEdit.Xml -{ - class TagMatchingHeuristics - { - const int maxConfigurationCount = 10; - - AXmlParser parser; - TrackedSegmentCollection trackedSegments; - string input; - List tags; - - public TagMatchingHeuristics(AXmlParser parser, string input, List tags) - { - this.parser = parser; - this.trackedSegments = parser.TrackedSegments; - this.input = input; - this.tags = tags; - } - - public AXmlDocument ReadDocument() - { - AXmlDocument doc = new AXmlDocument() { Parser = parser }; - - // AXmlParser.Log("Flat stream: {0}", PrintObjects(tags)); - List valid = MatchTags(tags); - // AXmlParser.Log("Fixed stream: {0}", PrintObjects(valid)); - IEnumerator validStream = valid.GetEnumerator(); - validStream.MoveNext(); // Move to first - while(true) { - // End of stream? - try { - if (validStream.Current == null) break; - } catch (InvalidCastException) { - break; - } - doc.AddChild(ReadTextOrElement(validStream)); - } - - if (doc.Children.Count > 0) { - doc.StartOffset = doc.FirstChild.StartOffset; - doc.EndOffset = doc.LastChild.EndOffset; - } - - // Check well formed - foreach(AXmlTag xmlDeclaration in doc.Children.OfType().Where(t => t.IsProcessingInstruction && string.Equals(t.Name, "xml", StringComparison.OrdinalIgnoreCase))) { - if (xmlDeclaration.StartOffset != 0) - TagReader.OnSyntaxError(doc, xmlDeclaration.StartOffset, xmlDeclaration.StartOffset + 5, - "XML declaration must be at the start of document"); - } - int elemCount = doc.Children.OfType().Count(); - if (elemCount == 0) - TagReader.OnSyntaxError(doc, doc.EndOffset, doc.EndOffset, - "Root element is missing"); - if (elemCount > 1) { - AXmlElement next = doc.Children.OfType().Skip(1).First(); - TagReader.OnSyntaxError(doc, next.StartOffset, next.StartOffset, - "Only one root element is allowed"); - } - foreach(AXmlTag tag in doc.Children.OfType()) { - if (tag.IsCData) - TagReader.OnSyntaxError(doc, tag.StartOffset, tag.EndOffset, - "CDATA not allowed in document root"); - } - foreach(AXmlText text in doc.Children.OfType()) { - if (!text.ContainsOnlyWhitespace) - TagReader.OnSyntaxError(doc, text.StartOffset, text.EndOffset, - "Only whitespace is allowed in document root"); - } - - - AXmlParser.Log("Constructed {0}", doc); - trackedSegments.AddParsedObject(doc, null); - return doc; - } - - static AXmlObject ReadSingleObject(IEnumerator objStream) - { - AXmlObject obj = objStream.Current; - objStream.MoveNext(); - return obj; - } - - AXmlObject ReadTextOrElement(IEnumerator objStream) - { - AXmlObject curr = objStream.Current; - if (curr is AXmlText || curr is AXmlElement) { - return ReadSingleObject(objStream); - } else { - AXmlTag currTag = (AXmlTag)curr; - if (currTag == StartTagPlaceholder) { - return ReadElement(objStream); - } else if (currTag.IsStartOrEmptyTag) { - return ReadElement(objStream); - } else { - return ReadSingleObject(objStream); - } - } - } - - AXmlElement ReadElement(IEnumerator objStream) - { - AXmlElement element = new AXmlElement(); - element.IsProperlyNested = true; - - // Read start tag - AXmlTag startTag = ReadSingleObject(objStream) as AXmlTag; - AXmlParser.DebugAssert(startTag != null, "Start tag expected"); - AXmlParser.DebugAssert(startTag.IsStartOrEmptyTag || startTag == StartTagPlaceholder, "Start tag expected"); - if (startTag == StartTagPlaceholder) { - element.HasStartOrEmptyTag = false; - element.IsProperlyNested = false; - TagReader.OnSyntaxError(element, objStream.Current.StartOffset, objStream.Current.EndOffset, - "Matching openning tag was not found"); - } else { - element.HasStartOrEmptyTag = true; - element.AddChild(startTag); - } - - // Read content and end tag - if (startTag == StartTagPlaceholder || // Check first in case the start tag is null - element.StartTag.IsStartTag) - { - while(true) { - AXmlTag currTag = objStream.Current as AXmlTag; // Peek - if (currTag == EndTagPlaceholder) { - TagReader.OnSyntaxError(element, element.LastChild.EndOffset, element.LastChild.EndOffset, - "Expected ''", element.StartTag.Name); - ReadSingleObject(objStream); - element.HasEndTag = false; - element.IsProperlyNested = false; - break; - } else if (currTag != null && currTag.IsEndTag) { - if (element.HasStartOrEmptyTag && currTag.Name != element.StartTag.Name) { - TagReader.OnSyntaxError(element, currTag.StartOffset + 2, currTag.StartOffset + 2 + currTag.Name.Length, - "Expected '{0}'. End tag must have same name as start tag.", element.StartTag.Name); - } - element.AddChild(ReadSingleObject(objStream)); - element.HasEndTag = true; - break; - } - AXmlObject nested = ReadTextOrElement(objStream); - - AXmlElement nestedAsElement = nested as AXmlElement; - if (nestedAsElement != null) { - if (!nestedAsElement.IsProperlyNested) - element.IsProperlyNested = false; - element.AddChildren(Split(nestedAsElement).ToList()); - } else { - element.AddChild(nested); - } - } - } else { - element.HasEndTag = false; - } - - element.StartOffset = element.FirstChild.StartOffset; - element.EndOffset = element.LastChild.EndOffset; - - AXmlParser.Assert(element.HasStartOrEmptyTag || element.HasEndTag, "Must have at least start or end tag"); - - AXmlParser.Log("Constructed {0}", element); - trackedSegments.AddParsedObject(element, null); // Need all elements in cache for offset tracking - return element; - } - - IEnumerable Split(AXmlElement elem) - { - int myIndention = GetIndentLevel(elem); - // Has start tag and no end tag ? (other then empty-element tag) - if (elem.HasStartOrEmptyTag && elem.StartTag.IsStartTag && !elem.HasEndTag && myIndention != -1) { - int lastAccepted = 0; // Accept start tag - while (lastAccepted + 1 < elem.Children.Count) { - AXmlObject nextItem = elem.Children[lastAccepted + 1]; - if (nextItem is AXmlText) { - lastAccepted++; continue; // Accept - } else { - // Include all more indented items - if (GetIndentLevel(nextItem) > myIndention) { - lastAccepted++; continue; // Accept - } else { - break; // Reject - } - } - } - // Accepted everything? - if (lastAccepted + 1 == elem.Children.Count) { - yield return elem; - yield break; - } - AXmlParser.Log("Splitting {0} - take {1} of {2} nested", elem, lastAccepted, elem.Children.Count - 1); - AXmlElement topHalf = new AXmlElement(); - topHalf.HasStartOrEmptyTag = elem.HasStartOrEmptyTag; - topHalf.HasEndTag = elem.HasEndTag; - topHalf.AddChildren(elem.Children.Take(1 + lastAccepted)); // Start tag + nested - topHalf.StartOffset = topHalf.FirstChild.StartOffset; - topHalf.EndOffset = topHalf.LastChild.EndOffset; - TagReader.OnSyntaxError(topHalf, topHalf.LastChild.EndOffset, topHalf.LastChild.EndOffset, - "Expected ''", topHalf.StartTag.Name); - - AXmlParser.Log("Constructed {0}", topHalf); - trackedSegments.AddParsedObject(topHalf, null); - yield return topHalf; - for(int i = lastAccepted + 1; i < elem.Children.Count; i++) { - yield return elem.Children[i]; - } - } else { - yield return elem; - } - } - - int GetIndentLevel(AXmlObject obj) - { - int offset = obj.StartOffset - 1; - int level = 0; - while(true) { - if (offset < 0) break; - char c = input[offset]; - if (c == ' ') { - level++; - } else if (c == '\t') { - level += 4; - } else if (c == '\r' || c == '\n') { - break; - } else { - return -1; - } - offset--; - } - return level; - } - - /// - /// Stack of still unmatched start tags. - /// It includes the cost and backtack information. - /// - class Configuration - { - /// Unmatched start tags - public ImmutableStack StartTags { get; set; } - /// Properly nested tags - public ImmutableStack Document { get; set; } - /// Number of needed modificaitons to the document - public int Cost { get; set; } - } - - /// - /// Dictionary which stores the cheapest configuration - /// - class Configurations: Dictionary, Configuration> - { - public Configurations() - { - } - - public Configurations(IEnumerable configs) - { - foreach(Configuration config in configs) { - this.Add(config); - } - } - - /// Overwrite only if cheaper - public void Add(Configuration newConfig) - { - Configuration oldConfig; - if (this.TryGetValue(newConfig.StartTags, out oldConfig)) { - if (newConfig.Cost < oldConfig.Cost) { - this[newConfig.StartTags] = newConfig; - } - } else { - base.Add(newConfig.StartTags, newConfig); - } - } - - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - foreach(var kvp in this) { - sb.Append("\n - '"); - foreach(AXmlTag startTag in kvp.Value.StartTags.Reverse()) { - sb.Append('<'); - sb.Append(startTag.Name); - sb.Append('>'); - } - sb.AppendFormat("' = {0}", kvp.Value.Cost); - } - return sb.ToString(); - } - } - - // Tags used to guide the element creation - readonly AXmlTag StartTagPlaceholder = new AXmlTag(); - readonly AXmlTag EndTagPlaceholder = new AXmlTag(); - - /// - /// Add start or end tag placeholders so that the documment is properly nested - /// - List MatchTags(IEnumerable objs) - { - Configurations configurations = new Configurations(); - configurations.Add(new Configuration { - StartTags = ImmutableStack.Empty, - Document = ImmutableStack.Empty, - Cost = 0, - }); - foreach(AXmlObject obj in objs) { - configurations = ProcessObject(configurations, obj); - } - // Close any remaining start tags - foreach(Configuration conifg in configurations.Values) { - while(!conifg.StartTags.IsEmpty) { - conifg.StartTags = conifg.StartTags.Pop(); - conifg.Document = conifg.Document.Push(EndTagPlaceholder); - conifg.Cost += 1; - } - } - // AXmlParser.Log("Configurations after closing all remaining tags:" + configurations.ToString()); - Configuration bestConfig = configurations.Values.OrderBy(v => v.Cost).First(); - AXmlParser.Log("Best configuration has cost {0}", bestConfig.Cost); - - return bestConfig.Document.Reverse().ToList(); - } - - /// Get posible configurations after considering given object - Configurations ProcessObject(Configurations oldConfigs, AXmlObject obj) - { - AXmlParser.Log("Processing {0}", obj); - - AXmlTag objAsTag = obj as AXmlTag; - AXmlElement objAsElement = obj as AXmlElement; - AXmlParser.DebugAssert(objAsTag != null || objAsElement != null || obj is AXmlText, obj.GetType().Name + " not expected"); - if (objAsElement != null) - AXmlParser.Assert(objAsElement.IsProperlyNested, "Element not properly nested"); - - Configurations newConfigs = new Configurations(); - - foreach(var kvp in oldConfigs) { - Configuration oldConfig = kvp.Value; - var oldStartTags = oldConfig.StartTags; - var oldDocument = oldConfig.Document; - int oldCost = oldConfig.Cost; - - if (objAsTag != null && objAsTag.IsStartTag) { - newConfigs.Add(new Configuration { // Push start-tag (cost 0) - StartTags = oldStartTags.Push(objAsTag), - Document = oldDocument.Push(objAsTag), - Cost = oldCost, - }); - } else if (objAsTag != null && objAsTag.IsEndTag) { - newConfigs.Add(new Configuration { // Ignore (cost 1) - StartTags = oldStartTags, - Document = oldDocument.Push(StartTagPlaceholder).Push(objAsTag), - Cost = oldCost + 1, - }); - if (!oldStartTags.IsEmpty && oldStartTags.Peek().Name != objAsTag.Name) { - newConfigs.Add(new Configuration { // Pop 1 item (cost 1) - not mathcing - StartTags = oldStartTags.Pop(), - Document = oldDocument.Push(objAsTag), - Cost = oldCost + 1, - }); - } - int popedCount = 0; - var startTags = oldStartTags; - var doc = oldDocument; - foreach(AXmlTag poped in oldStartTags) { - popedCount++; - if (poped.Name == objAsTag.Name) { - newConfigs.Add(new Configuration { // Pop 'x' items (cost x-1) - last one is matching - StartTags = startTags.Pop(), - Document = doc.Push(objAsTag), - Cost = oldCost + popedCount - 1, - }); - } - startTags = startTags.Pop(); - doc = doc.Push(EndTagPlaceholder); - } - } else { - // Empty tag or other tag type or text or properly nested element - newConfigs.Add(new Configuration { // Ignore (cost 0) - StartTags = oldStartTags, - Document = oldDocument.Push(obj), - Cost = oldCost, - }); - } - } - - // Log("New configurations:" + newConfigs.ToString()); - - Configurations bestNewConfigurations = new Configurations( - newConfigs.Values.OrderBy(v => v.Cost).Take(maxConfigurationCount) - ); - - // AXmlParser.Log("Best new configurations:" + bestNewConfigurations.ToString()); - - return bestNewConfigurations; - } - - #region Helper methods - /* - string PrintObjects(IEnumerable objs) - { - StringBuilder sb = new StringBuilder(); - foreach(AXmlObject obj in objs) { - if (obj is AXmlTag) { - if (obj == StartTagPlaceholder) { - sb.Append("#StartTag#"); - } else if (obj == EndTagPlaceholder) { - sb.Append("#EndTag#"); - } else { - sb.Append(((AXmlTag)obj).OpeningBracket); - sb.Append(((AXmlTag)obj).Name); - sb.Append(((AXmlTag)obj).ClosingBracket); - } - } else if (obj is AXmlElement) { - sb.Append('['); - sb.Append(PrintObjects(((AXmlElement)obj).Children)); - sb.Append(']'); - } else if (obj is AXmlText) { - sb.Append('~'); - } else { - throw new InternalException("Should not be here: " + obj); - } - } - return sb.ToString(); - } - */ - #endregion - } -} diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs index 7066f6300e..282a8dddfa 100644 --- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs +++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs @@ -35,7 +35,7 @@ using ICSharpCode.NRefactory.TypeSystem; namespace ICSharpCode.NRefactory.CSharp { - public abstract class AstNode : AbstractAnnotatable, ICSharpCode.NRefactory.TypeSystem.IFreezable, PatternMatching.INode + public abstract class AstNode : AbstractAnnotatable, ICSharpCode.NRefactory.TypeSystem.IFreezable, PatternMatching.INode, ICloneable { // the Root role must be available when creating the null nodes, so we can't put it in the Roles class internal static readonly Role RootRole = new Role ("Root"); @@ -613,6 +613,11 @@ namespace ICSharpCode.NRefactory.CSharp return copy; } + object ICloneable.Clone() + { + return Clone(); + } + public abstract void AcceptVisitor (IAstVisitor visitor); public abstract T AcceptVisitor (IAstVisitor visitor); diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs index bd81681bfa..1a3dbd3a36 100644 --- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs +++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractFreezable.cs @@ -59,6 +59,25 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (f != null) f.Freeze(); } + + public static T FreezeAndReturn(T item) where T : IFreezable + { + item.Freeze(); + return item; + } + + /// + /// If the item is not frozen, this method creates and returns a frozen clone. + /// If the item is already frozen, it is returned without creating a clone. + /// + public static T GetFrozenClone(T item) where T : IFreezable, ICloneable + { + if (!item.IsFrozen) { + item = (T)item.Clone(); + item.Freeze(); + } + return item; + } } [Serializable] diff --git a/src/Main/Base/Project/Workbench/File/FileService.cs b/src/Main/Base/Project/Workbench/File/FileService.cs index 0b9765c2ee..cc9cb61398 100644 --- a/src/Main/Base/Project/Workbench/File/FileService.cs +++ b/src/Main/Base/Project/Workbench/File/FileService.cs @@ -233,10 +233,5 @@ namespace ICSharpCode.SharpDevelop } #endregion Events - - public static object CreateUntitledOpenedFile(string plainFileName, byte[] byte1) - { - throw new NotImplementedException(); - } } } diff --git a/src/Main/SharpDevelop/Workbench/FileService.cs b/src/Main/SharpDevelop/Workbench/FileService.cs index c52a3b65c5..0d2c02311e 100644 --- a/src/Main/SharpDevelop/Workbench/FileService.cs +++ b/src/Main/SharpDevelop/Workbench/FileService.cs @@ -454,7 +454,7 @@ namespace ICSharpCode.SharpDevelop.Workbench try { IViewContent content = OpenFile(fileName); - IPositionable positionable = content.GetService(); + IPositionable positionable = content != null ? content.GetService() : null; if (positionable != null) { content.WorkbenchWindow.ActiveViewContent = content; NavigationService.ResumeLogging();