Browse Source

update AvalonEdit to 5.0.2

pull/478/merge
Siegfried Pammer 10 years ago
parent
commit
177519e19b
  1. 2
      AvalonEdit/Documentation/Code Completion.aml
  2. 192
      AvalonEdit/Documentation/ICSharpCode.AvalonEdit.shfbproj
  3. 563
      AvalonEdit/Documentation/License.html
  4. 10
      AvalonEdit/Documentation/Welcome.aml
  5. 57
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/ChangeTrackingTest.cs
  6. 19
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/CollapsingTests.cs
  7. 19
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/HeightTests.cs
  8. 28
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/LineManagerTests.cs
  9. 19
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/RandomizedLineManagerTest.cs
  10. 24
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/TextAnchorTest.cs
  11. 24
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/TextSegmentTreeTest.cs
  12. 22
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/TextUtilitiesTests.cs
  13. 92
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/UndoStackTests.cs
  14. 22
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Editing/ChangeDocumentTests.cs
  15. 56
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Editing/TextSegmentReadOnlySectionTests.cs
  16. 182
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HighlightedLineMergeTests.cs
  17. 27
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs
  18. 65
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj
  19. 44
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/MultipleUIThreads.cs
  20. 26
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Properties/AssemblyInfo.cs
  21. 22
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Search/FindTests.cs
  22. 76
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CaretNavigationTests.cs
  23. 55
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CompressingTreeListTests.cs
  24. 19
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/ExtensionMethodsTests.cs
  25. 19
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/IndentationStringTests.cs
  26. 19
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/RopeTests.cs
  27. 19
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/WeakReferenceTests.cs
  28. 223
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/ParserTests.cs
  29. 115
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/TextReplacementTests.cs
  30. BIN
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/W3C.zip
  31. 15
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/app.config
  32. 4
      AvalonEdit/ICSharpCode.AvalonEdit.Tests/packages.config
  33. 19
      AvalonEdit/ICSharpCode.AvalonEdit/AvalonEditCommands.cs
  34. 55
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs
  35. 2
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.xaml
  36. 19
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionListBox.cs
  37. 22
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs
  38. 23
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs
  39. 25
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/ICompletionData.cs
  40. 19
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/IOverloadProvider.cs
  41. 23
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs
  42. 4
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.xaml
  43. 21
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadInsightWindow.cs
  44. 19
      AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadViewer.cs
  45. 140
      AvalonEdit/ICSharpCode.AvalonEdit/Document/ChangeTrackingCheckpoint.cs
  46. 86
      AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentChangeEventArgs.cs
  47. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentChangeOperation.cs
  48. 32
      AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLine.cs
  49. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLineTree.cs
  50. 86
      AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentTextWriter.cs
  51. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Document/GapTextBuffer.cs
  52. 343
      AvalonEdit/ICSharpCode.AvalonEdit/Document/IDocument.cs
  53. 26
      AvalonEdit/ICSharpCode.AvalonEdit/Document/ILineTracker.cs
  54. 142
      AvalonEdit/ICSharpCode.AvalonEdit/Document/ITextAnchor.cs
  55. 389
      AvalonEdit/ICSharpCode.AvalonEdit/Document/ITextSource.cs
  56. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Document/IUndoableOperation.cs
  57. 46
      AvalonEdit/ICSharpCode.AvalonEdit/Document/LineManager.cs
  58. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs
  59. 28
      AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs
  60. 29
      AvalonEdit/ICSharpCode.AvalonEdit/Document/OffsetChangeMap.cs
  61. 169
      AvalonEdit/ICSharpCode.AvalonEdit/Document/RopeTextSource.cs
  62. 80
      AvalonEdit/ICSharpCode.AvalonEdit/Document/SimpleSegment.cs
  63. 86
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextAnchor.cs
  64. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextAnchorNode.cs
  65. 23
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextAnchorTree.cs
  66. 423
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs
  67. 22
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocumentWeakEventManager.cs
  68. 153
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextLocation.cs
  69. 40
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegment.cs
  70. 24
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegmentCollection.cs
  71. 136
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSourceVersionProvider.cs
  72. 170
      AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs
  73. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoOperationGroup.cs
  74. 24
      AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoStack.cs
  75. 28
      AvalonEdit/ICSharpCode.AvalonEdit/Document/WeakLineTracker.cs
  76. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/AbstractMargin.cs
  77. 83
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs
  78. 35
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretLayer.cs
  79. 257
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs
  80. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretWeakEventHandler.cs
  81. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/DottedLineMargin.cs
  82. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/DragDropException.cs
  83. 172
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs
  84. 32
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/EmptySelection.cs
  85. 23
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/IReadOnlySectionProvider.cs
  86. 221
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeNativeWrapper.cs
  87. 165
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeSupport.cs
  88. 42
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/LineNumberMargin.cs
  89. 26
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/NoReadOnlySections.cs
  90. 182
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs
  91. 64
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs
  92. 24
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionColorizer.cs
  93. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs
  94. 77
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs
  95. 23
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs
  96. 66
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs
  97. 117
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs
  98. 21
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs
  99. 19
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs
  100. 27
      AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextSegmentReadOnlySectionProvider.cs
  101. Some files were not shown because too many files have changed in this diff Show More

2
AvalonEdit/Documentation/Code Completion.aml

@ -123,7 +123,7 @@ public class MyCompletionData : ICompletionData @@ -123,7 +123,7 @@ public class MyCompletionData : ICompletionData
see:
<externalLink>
<linkText>Code Completion in SharpDevelop</linkText>
<linkUri>http://wiki.sharpdevelop.net/CodeCompletion.ashx</linkUri>
<linkUri>https://github.com/icsharpcode/SharpDevelop/wiki/Code-Completion</linkUri>
<linkTarget>_blank</linkTarget>
</externalLink>
</para>

192
AvalonEdit/Documentation/ICSharpCode.AvalonEdit.shfbproj

@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{850b6602-0a7f-413a-864a-e816b98d7407}</ProjectGuid>
<SHFBSchemaVersion>1.9.3.0</SHFBSchemaVersion>
<SHFBSchemaVersion>1.9.9.0</SHFBSchemaVersion>
<!-- AssemblyName, Name, and RootNamespace are not used by SHFB but Visual
Studio adds them anyway -->
<AssemblyName>Documentation</AssemblyName>
@ -31,126 +31,110 @@ @@ -31,126 +31,110 @@
</WorkingPath>
<BuildLogFile>
</BuildLogFile>
<FrameworkVersion>.NET 4.0.30319</FrameworkVersion>
<FrameworkVersion>.NET Framework 4.0</FrameworkVersion>
<HelpTitle>AvalonEdit</HelpTitle>
<CopyrightText>Copyright 2008-2011, Daniel Grunwald</CopyrightText>
<CopyrightText>Copyright 2008-2014, Daniel Grunwald</CopyrightText>
<PresentationStyle>Prototype</PresentationStyle>
<HelpFileVersion>4.1.0.0</HelpFileVersion>
<HelpFileVersion>4.4.0.0</HelpFileVersion>
<ComponentConfigurations>
<ComponentConfig id="Code Block Component" enabled="True">
<component id="Code Block Component" type="SandcastleBuilder.Components.CodeBlockComponent" assembly="{@SHFBFolder}SandcastleBuilder.Components.dll">
<!-- Base path for relative filenames in source attributes
(optional) -->
<basePath value="{@HtmlEncProjectFolder}" />
<!-- Connect to language filter (optional). If omitted,
language filtering is enabled by default. -->
<languageFilter value="true" />
<!-- Allow missing source files (Optional). If omitted,
it will generate errors if referenced source files
are missing. -->
<allowMissingSource value="false" />
<!-- Remove region markers from imported code blocks. If omitted,
region markers in imported code blocks are left alone. -->
<removeRegionMarkers value="false" />
<!-- Code colorizer options (required).
Attributes:
Language syntax configuration file (required)
XSLT style file (required)
"Copy" image file URL (required)
Default language (optional)
Enable line numbering (optional)
Enable outlining (optional)
Keep XML comment "see" tags within the code (optional)
Tab size override (optional, 0 = Use syntax file setting)
Use language name as default title (optional) -->
<colorizer syntaxFile="{@SHFBFolder}Colorizer\highlight.xml" styleFile="{@SHFBFolder}Colorizer\highlight.xsl" copyImageUrl="../icons/CopyCode.gif" language="cs" numberLines="false" outlining="false" keepSeeTags="false" tabSize="0" defaultTitle="true" />
<ComponentConfig id="Reflection Index Data (ESENT Cache)" enabled="True">
<component id="Reflection Index Data (ESENT Cache)">
<index name="reflection" value="/reflection/apis/api" key="@id" cache="15" localCacheSize="2500" frameworkCachePath="{@LocalDataFolder}Cache\ReflectionIndexCache" projectCachePath="">
<data base="{@SHFBFolder}Data\Reflection" recurse="true" files="*.xml" duplicateWarning="false" groupId="ReflectionIndexCache">
{@ReferenceLinkNamespaceFiles}
</data>
<data files="reflection.xml" groupId="Project_Ref_{@UniqueID}" />
</index>
<copy name="reflection" source="*" target="/document/reference" />
</component>
</ComponentConfig>
<ComponentConfig id="IntelliSense Component" enabled="True"><component id="IntelliSense Component" type="SandcastleBuilder.Components.IntelliSenseComponent" assembly="{@SHFBFolder}SandcastleBuilder.Components.dll">
<!-- Output options (optional)
Attributes:
Include Namespaces (false by default)
Namespaces filename ("Namespaces" if not specified or empty)
Directory (current folder if not specified or empty) -->
<output includeNamespaces="false" namespacesFile="Namespaces" folder="{@OutputFolder}" />
</component></ComponentConfig>
<ComponentConfig id="Cached MSDN URL References" enabled="True"><component id="Cached MSDN URL References" type="SandcastleBuilder.Components.CachedResolveReferenceLinksComponent" assembly="{@SHFBFolder}SandcastleBuilder.Components.dll" locale="{@Locale}" linkTarget="{@SdkLinkTarget}">
<helpOutput format="HtmlHelp1">
<cache filename="{@LocalDataFolder}Cache\MsdnUrl.cache" />
<targets base="{@SandcastlePath}Data\Reflection" recurse="true" files="*.xml" type="{@HtmlSdkLinkType}" />
<targets files="reflection.xml" type="Local" />
</helpOutput>
<helpOutput format="MSHelp2">
<cache filename="{@LocalDataFolder}Cache\MsdnUrl.cache" />
<targets base="{@SandcastlePath}Data\Reflection" recurse="true" files="*.xml" type="{@MSHelp2SdkLinkType}" />
<targets files="reflection.xml" type="Index" />
</helpOutput>
<helpOutput format="MSHelpViewer">
<cache filename="{@LocalDataFolder}Cache\MsdnUrl.cache" />
<targets base="{@SandcastlePath}Data\Reflection" recurse="true" files="*.xml" type="{@MSHelpViewerSdkLinkType}" />
<targets files="reflection.xml" type="Id" />
</helpOutput>
<helpOutput format="Website">
<cache filename="{@LocalDataFolder}Cache\MsdnUrl.cache" />
<targets base="{@SandcastlePath}Data\Reflection" recurse="true" files="*.xml" type="{@WebsiteSdkLinkType}" />
<targets files="reflection.xml" type="Local" />
</helpOutput>
<ComponentConfig id="Comments Index Data (ESENT Cache)" enabled="True"><component id="Comments Index Data (ESENT Cache)">
<index name="comments" value="/doc/members/member" key="@name" cache="30" localCacheSize="2500" frameworkCachePath="{@LocalDataFolder}Cache\CommentsIndexCache" projectCachePath="">
{@FrameworkCommentList}
{@CommentFileList}
</index>
<copy name="comments" source="*" target="/document/comments" />
</component></ComponentConfig>
<ComponentConfig id="Post-transform Component" enabled="True"><component id="Post-transform Component" type="SandcastleBuilder.Components.PostTransformComponent" assembly="{@SHFBFolder}SandcastleBuilder.Components.dll">
<!-- Code colorizer files (required).
Attributes:
Stylesheet file (required)
Script file (required)
"Copy" image file (required) -->
<colorizer stylesheet="{@SHFBFolder}Colorizer\highlight.css" scriptFile="{@SHFBFolder}Colorizer\highlight.js" copyImage="{@SHFBFolder}Colorizer\CopyCode.gif" />
<!-- Base output paths for the files (required). These should match
the parent folder of the output path of the HTML files (see
each of the SaveComponent instances below). -->
<outputPaths>
{@HelpFormatOutputPaths}
</outputPaths>
<!-- Logo image file (optional). Filename is required. The height,
width, altText, placement, and alignment attributes are
optional. -->
<logoFile filename="" height="0" width="0" altText="" placement="left" alignment="left" />
<ComponentConfig id="Code Block Component" enabled="True"><component id="Code Block Component">
<basePath value="{@HtmlEncProjectFolder}" />
<outputPaths>{@HelpFormatOutputPaths}</outputPaths>
<allowMissingSource value="false" />
<removeRegionMarkers value="false" />
<colorizer syntaxFile="{@SHFBFolder}Colorizer\highlight.xml" styleFile="{@SHFBFolder}Colorizer\highlight.xsl" stylesheet="{@SHFBFolder}Colorizer\highlight.css" scriptFile="{@SHFBFolder}Colorizer\highlight.js" disabled="{@DisableCodeBlockComponent}" language="cs" tabSize="0" numberLines="false" outlining="false" keepSeeTags="false" defaultTitle="true" />
</component></ComponentConfig>
<ComponentConfig id="Cached Reflection Index Data" enabled="True"><component id="Cached Reflection Index Data" type="SandcastleBuilder.Components.CachedCopyFromIndexComponent" assembly="{@SHFBFolder}SandcastleBuilder.Components.dll">
<index name="reflection" value="/reflection/apis/api" key="@id" cache="10">
<cache base="{@SandcastlePath}Data\Reflection" recurse="true" files="*.xml" cacheFile="{@LocalDataFolder}Cache\Reflection.cache" />
<data files="reflection.xml" />
</index>
<copy name="reflection" source="*" target="/document/reference" />
<ComponentConfig id="IntelliSense Component" enabled="True"><component id="IntelliSense Component"><!-- Output options (optional)
Attributes:
Include namespaces (false by default)
Namespaces comments filename ("Namespaces" if not specified or empty)
Output folder (current folder if not specified or empty) --><output includeNamespaces="false" namespacesFile="Namespaces" folder="{@OutputFolder}\..\IntelliSense" /></component></ComponentConfig>
<ComponentConfig id="Resolve Reference Links (ESENT Cache)" enabled="True"><component id="Resolve Reference Links (ESENT Cache)">
<locale value="{@Locale}" />
<linkTarget value="{@SdkLinkTarget}" />
<helpOutput format="HtmlHelp1">
<msdnContentIdCache path="{@LocalDataFolder}Cache\MsdnContentId.cache" cachePath="{@LocalDataFolder}Cache\ESentMsdnContentIdCache" localCacheSize="2500" />
<targets base="{@SHFBFolder}Data\Reflection" recurse="true" files="*.xml" type="{@HtmlSdkLinkType}" id="FrameworkTargets" cachePath="{@LocalDataFolder}Cache\ESentFrameworkTargetCache" localCacheSize="2500">
{@ReferenceLinkNamespaceFiles}
</targets>
<targets files="reflection.xml" type="Local" id="ProjectTargets" cachePath="" localCacheSize="2500" noReload="true" />
</helpOutput>
<helpOutput format="MSHelp2">
<msdnContentIdCache path="{@LocalDataFolder}Cache\MsdnContentId.cache" cachePath="{@LocalDataFolder}Cache\ESentMsdnContentIdCache" localCacheSize="2500" />
<targets base="{@SHFBFolder}Data\Reflection" recurse="true" files="*.xml" type="{@MSHelp2SdkLinkType}" id="FrameworkTargets" cachePath="{@LocalDataFolder}Cache\ESentFrameworkTargetCache" localCacheSize="2500">
{@ReferenceLinkNamespaceFiles}
</targets>
<targets files="reflection.xml" type="Index" id="ProjectTargets" cachePath="" localCacheSize="2500" noReload="true" />
</helpOutput>
<helpOutput format="MSHelpViewer">
<msdnContentIdCache path="{@LocalDataFolder}Cache\MsdnContentId.cache" cachePath="{@LocalDataFolder}Cache\ESentMsdnContentIdCache" localCacheSize="2500" />
<targets base="{@SHFBFolder}Data\Reflection" recurse="true" files="*.xml" type="{@MSHelpViewerSdkLinkType}" id="FrameworkTargets" cachePath="{@LocalDataFolder}Cache\ESentFrameworkTargetCache" localCacheSize="2500">
{@ReferenceLinkNamespaceFiles}
</targets>
<targets files="reflection.xml" type="Id" id="ProjectTargets" cachePath="" localCacheSize="2500" noReload="true" />
</helpOutput>
<helpOutput format="Website">
<msdnContentIdCache path="{@LocalDataFolder}Cache\MsdnContentId.cache" cachePath="{@LocalDataFolder}Cache\ESentMsdnContentIdCache" localCacheSize="2500" />
<targets base="{@SHFBFolder}Data\Reflection" recurse="true" files="*.xml" type="{@WebsiteSdkLinkType}" id="FrameworkTargets" cachePath="{@LocalDataFolder}Cache\ESentFrameworkTargetCache" localCacheSize="2500">
{@ReferenceLinkNamespaceFiles}
</targets>
<targets files="reflection.xml" type="Local" id="ProjectTargets" cachePath="" localCacheSize="2500" noReload="true" />
</helpOutput>
</component></ComponentConfig>
<ComponentConfig id="Cached Framework Comments Index Data" enabled="True"><component id="Cached Framework Comments Index Data" type="SandcastleBuilder.Components.CachedCopyFromIndexComponent" assembly="{@SHFBFolder}SandcastleBuilder.Components.dll">
<index name="comments" value="/doc/members/member" key="@name" cache="100">
{@CachedFrameworkCommentList}
{@CommentFileList}
</index>
<copy name="comments" source="*" target="/document/comments" />
</component></ComponentConfig></ComponentConfigurations>
<ComponentConfig id="API Token Resolution" enabled="True"><component id="API Token Resolution">{@TokenFiles}
<replace elements="/*//token" item="string(.)" /></component></ComponentConfig></ComponentConfigurations>
<DocumentationSources>
<DocumentationSource sourceFile="..\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj" />
</DocumentationSources>
<NamespaceSummaries>
<NamespaceSummaryItem name="(global)" isDocumented="False" />
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit" isDocumented="True">This is the main AvalonEdit namespace.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.CodeCompletion" isDocumented="True">This namespace contains classes to show the code completion window.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Document" isDocumented="True">This namespace contains the document model.
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit" isDocumented="True">This is the main AvalonEdit namespace.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.CodeCompletion" isDocumented="True">This namespace contains classes to show the code completion window.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Document" isDocumented="True">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.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Editing" isDocumented="True">This namespace is the home of the TextArea class. It manages user input and handles the caret and the selection.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Folding" isDocumented="True">This namespace contains the folding (code collapsing) implementation.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Highlighting" isDocumented="True">This namespace contains the engine for highlighting text documents (DocumentHighlighter).
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Editing" isDocumented="True">This namespace is the home of the TextArea class. It manages user input and handles the caret and the selection.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Folding" isDocumented="True">This namespace contains the folding (code collapsing) implementation.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Highlighting" isDocumented="True">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.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Highlighting.Xshd" isDocumented="True">This namespace contains a document model for syntax highlighting definitions (.xshd files).</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Indentation" isDocumented="True">This namespace contains the logic for automatic indentation.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Rendering" isDocumented="True">This namespace contains the text rendering infrastructure.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Utils" isDocumented="True">This namespace contains various utility classes.</NamespaceSummaryItem>
<NamespaceSummaryItem name="XamlGeneratedNamespace" isDocumented="False" />
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Xml" isDocumented="True">This namespace contains an error-tolerant XML parser with support for incremental parsing, only reparsing the changed regions of a TextDocument.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Snippets" isDocumented="True">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.</NamespaceSummaryItem>
</NamespaceSummaries>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Highlighting.Xshd" isDocumented="True">This namespace contains a document model for syntax highlighting definitions (.xshd files).</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Indentation" isDocumented="True">This namespace contains the logic for automatic indentation.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Rendering" isDocumented="True">This namespace contains the text rendering infrastructure.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Utils" isDocumented="True">This namespace contains various utility classes.</NamespaceSummaryItem>
<NamespaceSummaryItem name="XamlGeneratedNamespace" isDocumented="False" />
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Snippets" isDocumented="True">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.</NamespaceSummaryItem>
<NamespaceSummaryItem name="ICSharpCode.AvalonEdit.Search" isDocumented="True">This namespace contains the SearchPanel UI that allows the user to search the current document.</NamespaceSummaryItem></NamespaceSummaries>
<CleanIntermediates>True</CleanIntermediates>
<SyntaxFilters>Standard</SyntaxFilters>
<SdkLinkTarget>Blank</SdkLinkTarget>
<RootNamespaceContainer>False</RootNamespaceContainer>
<Preliminary>False</Preliminary>
<NamingMethod>Guid</NamingMethod>
<Language>en-US</Language>
<ContentPlacement>AboveNamespaces</ContentPlacement>
<BuildAssemblerVerbosity>OnlyWarningsAndErrors</BuildAssemblerVerbosity>
<HelpFileFormat>HtmlHelp1, Website</HelpFileFormat>
<IndentHtml>False</IndentHtml>
<KeepLogFile>True</KeepLogFile>
<DisableCodeBlockComponent>False</DisableCodeBlockComponent>
<CppCommentsFixup>False</CppCommentsFixup>
</PropertyGroup>
<!-- There are no properties for these two groups but they need to appear in
order for Visual Studio to perform the build. -->

563
AvalonEdit/Documentation/License.html

@ -2,565 +2,34 @@ @@ -2,565 +2,34 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>License</title>
<meta name="id" content="e41769b2-38f7-4605-b1d8-9cd22a50a685">
<meta name="revisionNumber" content="1"></meta>
<link rel="stylesheet" type="text/css" href="../styles/presentation.css" />
</head>
<body>
<h3>GNU LESSER GENERAL PUBLIC LICENSE</h3>
<p>
Version 2.1, February 1999
</p>
<pre>Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
</pre>
<h3>Preamble</h3>
<p>
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
</p>
<p>
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
</p>
<p>
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
</p>
<p>
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
</p>
<p>
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
</p>
<p>
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
</p>
<p>
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
</p>
<p>
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
</p>
<p>
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
</p>
<p>
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
</p>
<p>
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
</p>
<p>
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
</p>
<p>
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
</p>
<p>
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
</p>
<p>
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
</p>
<h3>TERMS AND CONDITIONS FOR COPYING,
DISTRIBUTION AND MODIFICATION</h3>
<p>
<strong>0.</strong>
This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
</p>
<p>
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
</p>
<p>
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
</p>
<p>
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
</p>
<p>
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
</p>
<p>
<strong>1.</strong>
You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
</p>
<p>
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
</p>
<p>
<strong>2.</strong>
You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
</p>
<h3>The MIT License (MIT)</h3>
<ul>
<li><strong>a)</strong>
The modified work must itself be a software library.</li>
<li><strong>b)</strong>
You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.</li>
<li><strong>c)</strong>
You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.</li>
<li><strong>d)</strong>
If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
<p>
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)</p></li>
</ul>
<p>
These requirements apply to the modified work as a whole. If identifiable
sections of that work are not derived from the Library, and can be
reasonably considered independent and separate works in themselves, then
this License, and its terms, do not apply to those sections when you
distribute them as separate works. But when you distribute the same
sections as part of a whole which is a work based on the Library, the
distribution of the whole must be on the terms of this License, whose
permissions for other licensees extend to the entire whole, and thus to
each and every part regardless of who wrote it.
</p>
<p>
Thus, it is not the intent of this section to claim rights or contest your
rights to work written entirely by you; rather, the intent is to exercise
the right to control the distribution of derivative or collective works
based on the Library.
</p>
<p>
In addition, mere aggregation of another work not based on the Library with
the Library (or with a work based on the Library) on a volume of a storage
or distribution medium does not bring the other work under the scope of
this License.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
</p>
<p>
<strong>3.</strong>
You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
</p>
<p>
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</p>
<p>
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
</p>
<p>
<strong>4.</strong>
You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
</p>
<p>
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
</p>
<p>
<strong>5.</strong>
A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
</p>
<p>
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
</p>
<p>
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
</p>
<p>
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
</p>
<p>
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
</p>
<p>
<strong>6.</strong>
As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
</p>
<p>
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
</p>
<ul>
<li><strong>a)</strong> Accompany the work with the complete
corresponding machine-readable source code for the Library
including whatever changes were used in the work (which must be
distributed under Sections 1 and 2 above); and, if the work is an
executable linked with the Library, with the complete
machine-readable "work that uses the Library", as object code
and/or source code, so that the user can modify the Library and
then relink to produce a modified executable containing the
modified Library. (It is understood that the user who changes the
contents of definitions files in the Library will not necessarily
be able to recompile the application to use the modified
definitions.)</li>
<li><strong>b)</strong> Use a suitable shared library mechanism
for linking with the Library. A suitable mechanism is one that
(1) uses at run time a copy of the library already present on the
user's computer system, rather than copying library functions into
the executable, and (2) will operate properly with a modified
version of the library, if the user installs one, as long as the
modified version is interface-compatible with the version that the
work was made with.</li>
<li><strong>c)</strong> Accompany the work with a written offer,
valid for at least three years, to give the same user the
materials specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.</li>
<li><strong>d)</strong> If distribution of the work is made by
offering access to copy from a designated place, offer equivalent
access to copy the above specified materials from the same
place.</li>
<li><strong>e)</strong> Verify that the user has already received
a copy of these materials or that you have already sent this user
a copy.</li>
</ul>
<p>
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
</p>
<p>
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
</p>
<p>
<strong>7.</strong> You may place library facilities that are a work
based on the Library side-by-side in a single library together with
other library facilities not covered by this License, and distribute
such a combined library, provided that the separate distribution of
the work based on the Library and of the other library facilities is
otherwise permitted, and provided that you do these two things:
</p>
<ul>
<li><strong>a)</strong> Accompany the combined library with a copy
of the same work based on the Library, uncombined with any other
library facilities. This must be distributed under the terms of
the Sections above.</li>
<li><strong>b)</strong> Give prominent notice with the combined
library of the fact that part of it is a work based on the
Library, and explaining where to find the accompanying uncombined
form of the same work.</li>
</ul>
<p>
<strong>8.</strong> You may not copy, modify, sublicense, link with,
or distribute the Library except as expressly provided under this
License. Any attempt otherwise to copy, modify, sublicense, link
with, or distribute the Library is void, and will automatically
terminate your rights under this License. However, parties who have
received copies, or rights, from you under this License will not have
their licenses terminated so long as such parties remain in full
compliance.
</p>
<p>
<strong>9.</strong>
You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
</p>
<p>
<strong>10.</strong>
Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
</p>
<p>
<strong>11.</strong>
If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
</p>
<p>
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
</p>
<p>
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
</p>
<p>
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
</p>
<p>
<strong>12.</strong>
If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
</p>
<p>
<strong>13.</strong>
The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
</p>
<p>
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
</p>
<p>
<strong>14.</strong>
If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
</p>
<p>
<strong>NO WARRANTY</strong>
</p>
<p>
<strong>15.</strong>
BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
</p>
<p>
<strong>16.</strong>
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
</p>
<h3>END OF TERMS AND CONDITIONS</h3>
</body>
</html>

10
AvalonEdit/Documentation/Welcome.aml

@ -41,13 +41,13 @@ @@ -41,13 +41,13 @@
<section>
<title>System requirements</title>
<content>
<para>AvalonEdit requires the
<para>There are two versions of AvalonEdit - the normal one requires
<externalLink>
<linkText>.NET Framework 3.5 SP1</linkText>
<linkUri>http://www.microsoft.com/downloads/details.aspx?FamilyID=ab99342f-5d1a-413d-8319-81da479ab0d7&amp;DisplayLang=en</linkUri>
<linkText>.NET Framework 4.0</linkText>
<linkUri>http://msdn.microsoft.com/en-us/library/w0x726c2.aspx</linkUri>
<linkTarget>_blank</linkTarget>
</externalLink>.
For compiling AvalonEdit inside Visual Studio 2008, VS08 SP1 is required.
</externalLink> or higher; but we also offer a modified version for .NET 3.5 SP1.
For compiling AvalonEdit, you will need a C# 4.0 compiler (SharpDevelop 4.x or Visual Studio 2010).
</para>
<para>AvalonEdit requires FullTrust and will not run as XBAP.</para>
</content>

57
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/ChangeTrackingTest.cs

@ -1,8 +1,26 @@ @@ -1,8 +1,26 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Document
@ -14,11 +32,10 @@ namespace ICSharpCode.AvalonEdit.Document @@ -14,11 +32,10 @@ namespace ICSharpCode.AvalonEdit.Document
public void NoChanges()
{
TextDocument document = new TextDocument("initial text");
ChangeTrackingCheckpoint checkpoint1, checkpoint2;
ITextSource snapshot1 = document.CreateSnapshot(out checkpoint1);
ITextSource snapshot2 = document.CreateSnapshot(out checkpoint2);
Assert.AreEqual(0, checkpoint1.CompareAge(checkpoint2));
Assert.AreEqual(0, checkpoint1.GetChangesTo(checkpoint2).Count());
ITextSource snapshot1 = document.CreateSnapshot();
ITextSource snapshot2 = document.CreateSnapshot();
Assert.AreEqual(0, snapshot1.Version.CompareAge(snapshot2.Version));
Assert.AreEqual(0, snapshot1.Version.GetChangesTo(snapshot2.Version).Count());
Assert.AreEqual(document.Text, snapshot1.Text);
Assert.AreEqual(document.Text, snapshot2.Text);
}
@ -27,16 +44,15 @@ namespace ICSharpCode.AvalonEdit.Document @@ -27,16 +44,15 @@ namespace ICSharpCode.AvalonEdit.Document
public void ForwardChanges()
{
TextDocument document = new TextDocument("initial text");
ChangeTrackingCheckpoint checkpoint1, checkpoint2;
ITextSource snapshot1 = document.CreateSnapshot(out checkpoint1);
ITextSource snapshot1 = document.CreateSnapshot();
document.Replace(0, 7, "nw");
document.Insert(1, "e");
ITextSource snapshot2 = document.CreateSnapshot(out checkpoint2);
Assert.AreEqual(-1, checkpoint1.CompareAge(checkpoint2));
DocumentChangeEventArgs[] arr = checkpoint1.GetChangesTo(checkpoint2).ToArray();
ITextSource snapshot2 = document.CreateSnapshot();
Assert.AreEqual(-1, snapshot1.Version.CompareAge(snapshot2.Version));
TextChangeEventArgs[] arr = snapshot1.Version.GetChangesTo(snapshot2.Version).ToArray();
Assert.AreEqual(2, arr.Length);
Assert.AreEqual("nw", arr[0].InsertedText);
Assert.AreEqual("e", arr[1].InsertedText);
Assert.AreEqual("nw", arr[0].InsertedText.Text);
Assert.AreEqual("e", arr[1].InsertedText.Text);
Assert.AreEqual("initial text", snapshot1.Text);
Assert.AreEqual("new text", snapshot2.Text);
@ -46,16 +62,15 @@ namespace ICSharpCode.AvalonEdit.Document @@ -46,16 +62,15 @@ namespace ICSharpCode.AvalonEdit.Document
public void BackwardChanges()
{
TextDocument document = new TextDocument("initial text");
ChangeTrackingCheckpoint checkpoint1, checkpoint2;
ITextSource snapshot1 = document.CreateSnapshot(out checkpoint1);
ITextSource snapshot1 = document.CreateSnapshot();
document.Replace(0, 7, "nw");
document.Insert(1, "e");
ITextSource snapshot2 = document.CreateSnapshot(out checkpoint2);
Assert.AreEqual(1, checkpoint2.CompareAge(checkpoint1));
DocumentChangeEventArgs[] arr = checkpoint2.GetChangesTo(checkpoint1).ToArray();
ITextSource snapshot2 = document.CreateSnapshot();
Assert.AreEqual(1, snapshot2.Version.CompareAge(snapshot1.Version));
TextChangeEventArgs[] arr = snapshot2.Version.GetChangesTo(snapshot1.Version).ToArray();
Assert.AreEqual(2, arr.Length);
Assert.AreEqual("", arr[0].InsertedText);
Assert.AreEqual("initial", arr[1].InsertedText);
Assert.AreEqual("", arr[0].InsertedText.Text);
Assert.AreEqual("initial", arr[1].InsertedText.Text);
Assert.AreEqual("initial text", snapshot1.Text);
Assert.AreEqual("new text", snapshot2.Text);

19
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/CollapsingTests.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.AvalonEdit.Rendering;

19
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/HeightTests.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;

28
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/LineManagerTests.cs

@ -1,8 +1,24 @@ @@ -1,8 +1,24 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Document
@ -31,10 +47,16 @@ namespace ICSharpCode.AvalonEdit.Document @@ -31,10 +47,16 @@ namespace ICSharpCode.AvalonEdit.Document
{
document.Text = "Hello,\nWorld!";
Assert.AreEqual(2, document.LineCount);
var oldLines = document.Lines.ToArray();
document.Text = "";
Assert.AreEqual("", document.Text);
Assert.AreEqual(0, document.TextLength);
Assert.AreEqual(1, document.LineCount);
Assert.AreSame(oldLines[0], document.Lines.Single());
Assert.IsFalse(oldLines[0].IsDeleted);
Assert.IsTrue(oldLines[1].IsDeleted);
Assert.IsNull(oldLines[0].NextLine);
Assert.IsNull(oldLines[1].PreviousLine);
}
[Test]
@ -105,7 +127,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -105,7 +127,7 @@ namespace ICSharpCode.AvalonEdit.Document
[Test, ExpectedException(typeof(ArgumentNullException))]
public void InsertNull()
{
document.Insert(0, null);
document.Insert(0, (string)null);
}
[Test, ExpectedException(typeof(ArgumentNullException))]

19
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/RandomizedLineManagerTest.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;

24
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/TextAnchorTest.cs

@ -1,9 +1,27 @@ @@ -1,9 +1,27 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using NUnit.Framework;
using System.Collections.Generic;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Document
{

24
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/TextSegmentTreeTest.cs

@ -1,9 +1,27 @@ @@ -1,9 +1,27 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using NUnit.Framework;
using System.Collections.Generic;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Document
{

22
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/TextUtilitiesTests.cs

@ -1,7 +1,25 @@ @@ -1,7 +1,25 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Document

92
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Document/UndoStackTests.cs

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Document
{
public class UndoStackTests
{
[Test]
public void ContinueUndoGroup()
{
var doc = new TextDocument();
doc.Insert(0, "a");
doc.UndoStack.StartContinuedUndoGroup();
doc.Insert(1, "b");
doc.UndoStack.EndUndoGroup();
doc.UndoStack.Undo();
Assert.AreEqual("", doc.Text);
}
[Test]
public void ContinueEmptyUndoGroup()
{
var doc = new TextDocument();
doc.Insert(0, "a");
doc.UndoStack.StartUndoGroup();
doc.UndoStack.EndUndoGroup();
doc.UndoStack.StartContinuedUndoGroup();
doc.Insert(1, "b");
doc.UndoStack.EndUndoGroup();
doc.UndoStack.Undo();
Assert.AreEqual("a", doc.Text);
}
[Test]
public void ContinueEmptyUndoGroup_WithOptionalEntries()
{
var doc = new TextDocument();
doc.Insert(0, "a");
doc.UndoStack.StartUndoGroup();
doc.UndoStack.PushOptional(new StubUndoableAction());
doc.UndoStack.EndUndoGroup();
doc.UndoStack.StartContinuedUndoGroup();
doc.Insert(1, "b");
doc.UndoStack.EndUndoGroup();
doc.UndoStack.Undo();
Assert.AreEqual("a", doc.Text);
}
[Test]
public void EmptyContinuationGroup()
{
var doc = new TextDocument();
doc.Insert(0, "a");
doc.UndoStack.StartContinuedUndoGroup();
doc.UndoStack.EndUndoGroup();
doc.UndoStack.StartContinuedUndoGroup();
doc.Insert(1, "b");
doc.UndoStack.EndUndoGroup();
doc.UndoStack.Undo();
Assert.AreEqual("", doc.Text);
}
class StubUndoableAction : IUndoableOperation
{
public void Undo()
{
}
public void Redo()
{
}
}
}
}

22
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Editing/ChangeDocumentTests.cs

@ -1,9 +1,27 @@ @@ -1,9 +1,27 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Text;
using ICSharpCode.AvalonEdit.Document;
#if NREFACTORY
using ICSharpCode.NRefactory;
#endif
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Editing

56
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Editing/TextSegmentReadOnlySectionTests.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.AvalonEdit.Document;
using System;
@ -37,6 +52,15 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -37,6 +52,15 @@ namespace ICSharpCode.AvalonEdit.Editing
Assert.AreEqual(20, result[0].Length);
}
[Test]
public void EmptyDeletionPossibleWhenNothingIsReadOnly()
{
var result = provider.GetDeletableSegments(new SimpleSegment(10, 0)).ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual(10, result[0].Offset);
Assert.AreEqual(0, result[0].Length);
}
[Test]
public void InsertionPossibleBeforeReadOnlySegment()
{
@ -84,6 +108,34 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -84,6 +108,34 @@ namespace ICSharpCode.AvalonEdit.Editing
Assert.AreEqual(0, result.Count);
}
[Test]
public void EmptyDeletionImpossibleInReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(11, 0)).ToList();
Assert.AreEqual(0, result.Count);
}
[Test]
public void EmptyDeletionPossibleAtStartOfReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(10, 0)).ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual(10, result[0].Offset);
Assert.AreEqual(0, result[0].Length);
}
[Test]
public void EmptyDeletionPossibleAtEndOfReadOnlySegment()
{
segments.Add(new TextSegment { StartOffset = 10, Length = 5 });
var result = provider.GetDeletableSegments(new SimpleSegment(15, 0)).ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual(15, result[0].Offset);
Assert.AreEqual(0, result[0].Length);
}
[Test]
public void DeletionAroundReadOnlySegment()
{

182
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HighlightedLineMergeTests.cs

@ -0,0 +1,182 @@ @@ -0,0 +1,182 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.NRefactory.Editor;
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Highlighting
{
[TestFixture]
public class HighlightedLineMergeTests
{
IDocument document = new TextDocument(new string(' ', 20));
[Test]
public void SimpleMerge1()
{
HighlightedLine baseLine = new HighlightedLine(document, document.GetLineByNumber(1));
baseLine.Sections.Add(MakeSection(0, 1, "B"));
HighlightedLine additionalLine = new HighlightedLine(document, document.GetLineByNumber(1));
additionalLine.Sections.Add(MakeSection(0, 2, "A"));
baseLine.MergeWith(additionalLine);
// The additional section gets split up so that it fits into the tree structure
Assert.That(baseLine.Sections, Is.EqualTo(
new[] {
MakeSection(0, 1, "B"),
MakeSection(0, 1, "A"),
MakeSection(1, 2, "A")
}).Using(new SectionComparer()));
}
[Test]
public void SimpleMerge2()
{
HighlightedLine baseLine = new HighlightedLine(document, document.GetLineByNumber(1));
baseLine.Sections.Add(MakeSection(0, 1, "B"));
baseLine.Sections.Add(MakeSection(0, 1, "BN"));
HighlightedLine additionalLine = new HighlightedLine(document, document.GetLineByNumber(1));
additionalLine.Sections.Add(MakeSection(0, 2, "A"));
baseLine.MergeWith(additionalLine);
// The additional section gets split up so that it fits into the tree structure
Assert.That(baseLine.Sections, Is.EqualTo(
new[] {
MakeSection(0, 1, "B"),
MakeSection(0, 1, "BN"),
MakeSection(0, 1, "A"),
MakeSection(1, 2, "A")
}).Using(new SectionComparer()));
}
HighlightedSection MakeSection(int start, int end, string name)
{
return new HighlightedSection { Offset = start, Length = end - start, Color = new HighlightingColor { Name = name }};
}
class SectionComparer : IEqualityComparer<HighlightedSection>
{
public bool Equals(HighlightedSection a, HighlightedSection b)
{
return a.Offset == b.Offset && a.Length == b.Length && a.Color.Name == b.Color.Name;
}
public int GetHashCode(HighlightedSection obj)
{
return obj.Offset;
}
}
#region Automatic Test
/*
const int combinations = 6 * 3 * 4 * 3 * 3 * 4;
HighlightingColor[] baseLineColors = {
new HighlightingColor { Name = "Base-A" },
new HighlightingColor { Name = "Base-B" },
new HighlightingColor { Name = "Base-N" },
new HighlightingColor { Name = "Base-C" }
};
HighlightingColor[] additionalLineColors = {
new HighlightingColor { Name = "Add-A" },
new HighlightingColor { Name = "Add-B" },
new HighlightingColor { Name = "Add-N" },
new HighlightingColor { Name = "Add-C" }
};
HighlightedLine BuildHighlightedLine(int num, HighlightingColor[] colors)
{
// We are build a HighlightedLine with 4 segments:
// A B C (top-level) and N nested within B.
// These are the integers controlling the generating process:
int aStart = GetNum(ref num, 5); // start offset of A
int aLength = GetNum(ref num, 2); // length of A
int bDistance = GetNum(ref num, 3); // distance from start of B to end of A
int bStart = aStart + aLength + bDistance;
int nDistance = GetNum(ref num, 2); // distance from start of B to start of N, range 0-2
int nLength = GetNum(ref num, 2); // length of N
int bEndDistance = GetNum(ref num, 2); // distance from end of N to end of B
int bLength = nDistance + nLength + bEndDistance;
int cDistance = GetNum(ref num, 3); // distance from end of B to start of C
int cStart = bStart + bLength + cDistance;
int cLength = 1;
Assert.AreEqual(0, num);
var documentLine = document.GetLineByNumber(1);
HighlightedLine line = new HighlightedLine(document, documentLine);
line.Sections.Add(new HighlightedSection { Offset = aStart, Length = aLength, Color = colors[0] });
line.Sections.Add(new HighlightedSection { Offset = bStart, Length = bLength, Color = colors[1] });
line.Sections.Add(new HighlightedSection { Offset = bStart + nDistance, Length = nLength, Color = colors[2] });
line.Sections.Add(new HighlightedSection { Offset = cStart, Length = cLength, Color = colors[3] });
return line;
}
/// <summary>
/// Gets a number between 0 and max (inclusive)
/// </summary>
int GetNum(ref int num, int max)
{
int result = num % (max+1);
num = num / (max + 1);
return result;
}
[Test]
public void TestAll()
{
for (int c1 = 0; c1 < combinations; c1++) {
HighlightedLine line1 = BuildHighlightedLine(c1, additionalLineColors);
for (int c2 = 0; c2 < combinations; c2++) {
HighlightedLine line2 = BuildHighlightedLine(c2, baseLineColors);
HighlightingColor[] expectedPerCharColors = new HighlightingColor[document.TextLength];
ApplyColors(expectedPerCharColors, line2);
ApplyColors(expectedPerCharColors, line1);
try {
line2.MergeWith(line1);
} catch (InvalidOperationException ex) {
throw new InvalidOperationException(string.Format("Error for c1 = {0}, c2 = {1}", c1, c2), ex);
}
HighlightingColor[] actualPerCharColors = new HighlightingColor[document.TextLength];
ApplyColors(actualPerCharColors, line2);
Assert.AreEqual(expectedPerCharColors, actualPerCharColors, string.Format("c1 = {0}, c2 = {1}", c1, c2));
}
}
}
void ApplyColors(HighlightingColor[] perCharColors, HighlightedLine line)
{
foreach (var section in line.Sections) {
for (int i = 0; i < section.Length; i++) {
perCharColors[section.Offset + i] = section.Color;
}
}
}
*/
#endregion
}
}

27
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Highlighting/HtmlClipboardTests.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
@ -17,7 +32,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting @@ -17,7 +32,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting
public HtmlClipboardTests()
{
document = new TextDocument("using System.Text;\n\tstring text = SomeMethod();");
highlighter = new DocumentHighlighter(document, HighlightingManager.Instance.GetDefinition("C#").MainRuleSet);
highlighter = new DocumentHighlighter(document, HighlightingManager.Instance.GetDefinition("C#"));
}
[Test]
@ -25,9 +40,9 @@ namespace ICSharpCode.AvalonEdit.Highlighting @@ -25,9 +40,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("<span style=\"color: #008000; font-weight: bold; \">using</span>&nbsp;System.Text;<br>" + Environment.NewLine +
"&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color: #ff0000; \">string</span>&nbsp;" +
"text =&nbsp;<span style=\"color: #191970; font-weight: bold; \">SomeMethod</span>();", html);
Assert.AreEqual("<span style=\"color: #008000; font-weight: bold; \">using</span> System.Text;<br>" + Environment.NewLine +
"&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color: #ff0000; \">string</span> " +
"text = <span style=\"color: #191970; font-weight: bold; \">SomeMethod</span>();", html);
}
[Test]

65
AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj

@ -3,13 +3,12 @@ @@ -3,13 +3,12 @@
<PropertyGroup>
<ProjectGuid>{6222A3A1-83CE-47A3-A4E4-A018F82D44D8}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<Platform Condition=" '$(Platform)' == '' ">Net40</Platform>
<OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.AvalonEdit</RootNamespace>
<AssemblyName>ICSharpCode.AvalonEdit.Tests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion Condition=" '$(Configuration)' == '' ">v4.0</TargetFrameworkVersion>
<AppDesignerFolder>Properties</AppDesignerFolder>
<SourceAnalysisOverrideSettingsFile>"C:\Program Files\SharpDevelop\3.0\bin\..\AddIns\AddIns\Misc\SourceAnalysis\Settings.SourceAnalysis"</SourceAnalysisOverrideSettingsFile>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>..\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign>
@ -17,39 +16,55 @@ @@ -17,39 +16,55 @@
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<OutputPath>..\..\..\..\bin\UnitTests\</OutputPath>
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
<OutputPath>bin\$(Configuration)\</OutputPath>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<NoWin32Manifest>False</NoWin32Manifest>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>AnyCPU</PlatformTarget>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'Net35' ">
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'Net40' ">
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<DefineConstants>DOTNET4</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'WithNRefactory' ">
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<DefineConstants>NREFACTORY</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<DefineDebug>True</DefineDebug>
<DefineTrace>True</DefineTrace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>false</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>x86</PlatformTarget>
<FileAlignment>4096</FileAlignment>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<DefineTrace>True</DefineTrace>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup>
<Reference Include="ICSharpCode.SharpZipLib">
<HintPath>..\..\..\AddIns\Misc\AddInManager\RequiredLibraries\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<ProjectReference Include="..\..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj" Condition="$(DefineConstants.Contains('NREFACTORY'))">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
<Reference Include="nunit.framework">
<HintPath>..\..\..\Tools\NUnit\nunit.framework.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\NUnit.2.6.3\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="PresentationCore">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
@ -77,9 +92,12 @@ @@ -77,9 +92,12 @@
<Compile Include="Document\TextAnchorTest.cs" />
<Compile Include="Document\TextSegmentTreeTest.cs" />
<Compile Include="Document\TextUtilitiesTests.cs" />
<Compile Include="Document\UndoStackTests.cs" />
<Compile Include="Editing\ChangeDocumentTests.cs" />
<Compile Include="Editing\TextSegmentReadOnlySectionTests.cs" />
<Compile Include="Highlighting\HighlightedLineMergeTests.cs" />
<Compile Include="Highlighting\HtmlClipboardTests.cs" />
<Compile Include="MultipleUIThreads.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Document\CollapsingTests.cs" />
<Compile Include="Document\HeightTests.cs" />
@ -92,12 +110,6 @@ @@ -92,12 +110,6 @@
<Compile Include="Utils\IndentationStringTests.cs" />
<Compile Include="Utils\RopeTests.cs" />
<Compile Include="WeakReferenceTests.cs" />
<Compile Include="XmlParser\ParserTests.cs" />
<Compile Include="XmlParser\TextReplacementTests.cs" />
<None Include="app.config" />
<None Include="XmlParser\W3C.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.AvalonEdit\ICSharpCode.AvalonEdit.csproj">
@ -108,4 +120,7 @@ @@ -108,4 +120,7 @@
<ItemGroup>
<Folder Include="Search" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

44
AvalonEdit/ICSharpCode.AvalonEdit.Tests/MultipleUIThreads.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// 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.Threading;
using System.Windows;
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit
{
[TestFixture]
public class MultipleUIThreads
{
Exception error;
[Test]
public void CreateEditorInstancesOnMultipleUIThreads()
{
Thread t1 = new Thread(new ThreadStart(Run));
Thread t2 = new Thread(new ThreadStart(Run));
t1.SetApartmentState(ApartmentState.STA);
t2.SetApartmentState(ApartmentState.STA);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
if (error != null)
throw new InvalidOperationException(error.Message, error);
}
[STAThread]
void Run()
{
try {
var window = new Window();
window.Content = new TextEditor();
window.ShowActivated = false;
window.Show();
} catch (Exception ex) {
error = ex;
}
}
}
}

26
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Properties/AssemblyInfo.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#region Using directives
@ -7,6 +22,8 @@ using System; @@ -7,6 +22,8 @@ using System;
using System.Reflection;
using System.Runtime.InteropServices;
using NUnit.Framework;
#endregion
// General Information about an assembly is controlled through the following
@ -31,3 +48,8 @@ using System.Runtime.InteropServices; @@ -31,3 +48,8 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
// Run unit tests on STA thread.
[assembly: RequiresSTA]
namespace ICSharpCode.NRefactory.Editor {}

22
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Search/FindTests.cs

@ -1,9 +1,27 @@ @@ -1,9 +1,27 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using ICSharpCode.AvalonEdit.Document;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Search

76
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CaretNavigationTests.cs

@ -1,9 +1,27 @@ @@ -1,9 +1,27 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Documents;
using ICSharpCode.AvalonEdit.Document;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Utils
@ -82,5 +100,59 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -82,5 +100,59 @@ namespace ICSharpCode.AvalonEdit.Utils
Assert.AreEqual(0, GetPrevCaretStop("txt ", 5, CaretPositioningMode.WordStart));
Assert.AreEqual(3, GetPrevCaretStop("txt ", 5, CaretPositioningMode.WordBorder));
}
[Test]
public void SingleCharacterOutsideBMP()
{
string c = "\U0001D49E";
Assert.AreEqual(2, GetNextCaretStop(c, 0, CaretPositioningMode.Normal));
Assert.AreEqual(0, GetPrevCaretStop(c, 2, CaretPositioningMode.Normal));
}
[Test]
public void DetectWordBordersOutsideBMP()
{
string c = " a\U0001D49Eb ";
Assert.AreEqual(1, GetNextCaretStop(c, 0, CaretPositioningMode.WordBorder));
Assert.AreEqual(5, GetNextCaretStop(c, 1, CaretPositioningMode.WordBorder));
Assert.AreEqual(5, GetPrevCaretStop(c, 6, CaretPositioningMode.WordBorder));
Assert.AreEqual(1, GetPrevCaretStop(c, 5, CaretPositioningMode.WordBorder));
}
[Test]
public void DetectWordBordersOutsideBMP2()
{
string c = " \U0001D49E\U0001D4AA ";
Assert.AreEqual(1, GetNextCaretStop(c, 0, CaretPositioningMode.WordBorder));
Assert.AreEqual(5, GetNextCaretStop(c, 1, CaretPositioningMode.WordBorder));
Assert.AreEqual(5, GetPrevCaretStop(c, 6, CaretPositioningMode.WordBorder));
Assert.AreEqual(1, GetPrevCaretStop(c, 5, CaretPositioningMode.WordBorder));
}
[Test]
public void CombiningMark()
{
string str = " x͆ ";
Assert.AreEqual(3, GetNextCaretStop(str, 1, CaretPositioningMode.Normal));
Assert.AreEqual(1, GetPrevCaretStop(str, 3, CaretPositioningMode.Normal));
}
[Test]
public void StackedCombiningMark()
{
string str = " x͆͆͆͆ ";
Assert.AreEqual(6, GetNextCaretStop(str, 1, CaretPositioningMode.Normal));
Assert.AreEqual(1, GetPrevCaretStop(str, 6, CaretPositioningMode.Normal));
}
[Test]
public void SingleClosingBraceAtLineEnd()
{
string str = "\t\t}";
Assert.AreEqual(2, GetNextCaretStop(str, 1, CaretPositioningMode.WordStart));
Assert.AreEqual(-1, GetPrevCaretStop(str, 1, CaretPositioningMode.WordStart));
}
}
}

55
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/CompressingTreeListTests.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
@ -30,12 +45,7 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -30,12 +45,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<OverflowException>(delegate { list.InsertRange(2, billion, "C"); });
}
[Test]
@ -103,5 +113,34 @@ namespace ICSharpCode.AvalonEdit.Utils @@ -103,5 +113,34 @@ namespace ICSharpCode.AvalonEdit.Utils
list.RemoveRange(0, 3);
Assert.AreEqual(new[] { 2, 3, 3 }, list.ToArray());
}
[Test]
public void Transform()
{
CompressingTreeList<int> list = new CompressingTreeList<int>((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<int> list = new CompressingTreeList<int>((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<int> list = new CompressingTreeList<int>((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());
}
}
}

19
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/ExtensionMethodsTests.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using NUnit.Framework;

19
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/IndentationStringTests.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using NUnit.Framework;

19
AvalonEdit/ICSharpCode.AvalonEdit.Tests/Utils/RopeTests.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;

19
AvalonEdit/ICSharpCode.AvalonEdit.Tests/WeakReferenceTests.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Threading;

223
AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/ParserTests.cs

@ -1,223 +0,0 @@ @@ -1,223 +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.Diagnostics;
using System.IO;
using System.Text;
using ICSharpCode.AvalonEdit.Xml;
using ICSharpCode.SharpZipLib.Zip;
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Xml
{
class TestFile
{
public string Name { get; set; }
public string Content { get; set; }
public string Canonical { get; set; }
public string Description { get; set; }
}
[TestFixture]
public class ParserTests
{
readonly string zipFileName = @"XmlParser\W3C.zip";
List<TestFile> xmlFiles = new List<TestFile>();
[TestFixtureSetUp]
public void OpenZipFile()
{
ZipFile zipFile = new ZipFile(zipFileName);
Dictionary<string, TestFile> xmlFiles = new Dictionary<string, TestFile>();
// Decompress XML files
foreach(ZipEntry zipEntry in zipFile.Cast<ZipEntry>().Where(zip => zip.IsFile && zip.Name.EndsWith(".xml"))) {
Stream stream = zipFile.GetInputStream(zipEntry);
string content = new StreamReader(stream).ReadToEnd();
xmlFiles.Add(zipEntry.Name, new TestFile { Name = zipEntry.Name, Content = content });
}
// Add descriptions
foreach(TestFile metaData in xmlFiles.Values.Where(f => f.Name.StartsWith("ibm/ibm_oasis"))) {
var doc = System.Xml.Linq.XDocument.Parse(metaData.Content);
foreach(var testElem in doc.Descendants("TEST")) {
string uri = "ibm/" + testElem.Attribute("URI").Value;
string description = testElem.Value.Replace("\n ", "\n").TrimStart('\n');
if (xmlFiles.ContainsKey(uri))
xmlFiles[uri].Description = description;
}
}
// Copy canonical forms
foreach(TestFile canonical in xmlFiles.Values.Where(f => f.Name.Contains("/out/"))) {
string uri = canonical.Name.Replace("/out/", "/");
if (xmlFiles.ContainsKey(uri))
xmlFiles[uri].Canonical = canonical.Content;
}
// Copy resuts to field
this.xmlFiles.AddRange(xmlFiles.Values.Where(f => !f.Name.Contains("/out/")));
}
IEnumerable<TestFile> GetXmlFilesStartingWith(string directory)
{
return xmlFiles.Where(f => f.Name.StartsWith(directory));
}
[Test]
public void W3C_Valid()
{
string[] exclude = {
// NAME in DTD infoset
"ibm02v01", "ibm03v01", "ibm85v01", "ibm86v01", "ibm87v01", "ibm88v01", "ibm89v01",
};
TestFiles(GetXmlFilesStartingWith("ibm/valid/"), true, exclude);
}
[Test]
public void W3C_Invalid()
{
string[] exclude = {
// Default attribute value
"ibm56i03",
};
TestFiles(GetXmlFilesStartingWith("ibm/invalid/"), true, exclude);
}
[Test]
public void W3C_NotWellformed()
{
string[] exclude = {
// XML declaration well formed
"ibm23n", "ibm24n", "ibm26n01", "ibm32n", "ibm80n06", "ibm81n01", "ibm81n02", "ibm81n03", "ibm81n04", "ibm81n05", "ibm81n06", "ibm81n07", "ibm81n08", "ibm81n09",
// Invalid chars in a comment - do we care?
"ibm02n",
// Invalid char ref - do we care?
"ibm66n12", "ibm66n13", "ibm66n14", "ibm66n15",
// DTD in wrong location
"ibm27n01", "ibm43n",
// Entity refs depending on DTD
"ibm41n10", "ibm41n11", "ibm41n12", "ibm41n13", "ibm41n14", "ibm68n04", "ibm68n06", "ibm68n07", "ibm68n08", "ibm68n09", "ibm68n10",
// DTD Related tests
"ibm09n01", "ibm09n02", "ibm13n01", "ibm13n02", "ibm13n03", "ibm28n01", "ibm28n02", "ibm28n03", "ibm29n01", "ibm29n03", "ibm29n04", "ibm29n07", "ibm30n01", "ibm31n01", "ibm45n01", "ibm45n02", "ibm45n03", "ibm45n04", "ibm45n05", "ibm45n06", "ibm46n01", "ibm46n02", "ibm46n03", "ibm46n04",
"ibm46n05", "ibm47n01", "ibm47n02", "ibm47n03", "ibm47n04", "ibm47n05", "ibm47n06", "ibm48n01", "ibm48n02", "ibm48n03", "ibm48n04", "ibm48n05", "ibm48n06", "ibm48n07", "ibm49n01", "ibm49n02", "ibm49n03", "ibm49n04", "ibm49n05", "ibm49n06", "ibm50n01", "ibm50n02", "ibm50n03", "ibm50n04",
"ibm50n05", "ibm50n06", "ibm50n07", "ibm51n01", "ibm51n02", "ibm51n03", "ibm51n04", "ibm51n05", "ibm51n06", "ibm51n07", "ibm52n01", "ibm52n02", "ibm52n03", "ibm53n01", "ibm53n02", "ibm53n03", "ibm53n04", "ibm53n05", "ibm53n06", "ibm53n07", "ibm53n08", "ibm54n01", "ibm54n02", "ibm55n01",
"ibm55n02", "ibm55n03", "ibm56n01", "ibm56n02", "ibm56n03", "ibm56n04", "ibm56n05", "ibm56n06", "ibm56n07", "ibm57n01", "ibm58n01", "ibm58n02", "ibm58n03", "ibm58n04", "ibm58n05", "ibm58n06", "ibm58n07", "ibm58n08", "ibm59n01", "ibm59n02", "ibm59n03", "ibm59n04", "ibm59n05", "ibm59n06",
"ibm60n01", "ibm60n02", "ibm60n03", "ibm60n04", "ibm60n05", "ibm60n06", "ibm60n07", "ibm60n08", "ibm61n01", "ibm62n01", "ibm62n02", "ibm62n03", "ibm62n04", "ibm62n05", "ibm62n06", "ibm62n07", "ibm62n08", "ibm63n01", "ibm63n02", "ibm63n03", "ibm63n04", "ibm63n05", "ibm63n06", "ibm63n07",
"ibm64n01", "ibm64n02", "ibm64n03", "ibm65n01", "ibm65n02", "ibm66n01", "ibm66n03", "ibm66n05", "ibm66n07", "ibm66n09", "ibm66n11", "ibm69n01", "ibm69n02", "ibm69n03", "ibm69n04", "ibm69n05", "ibm69n06", "ibm69n07", "ibm70n01", "ibm71n01", "ibm71n02", "ibm71n03", "ibm71n04", "ibm71n05",
"ibm72n01", "ibm72n02", "ibm72n03", "ibm72n04", "ibm72n05", "ibm72n06", "ibm72n09", "ibm73n01", "ibm73n03", "ibm74n01", "ibm75n01", "ibm75n02", "ibm75n03", "ibm75n04", "ibm75n05", "ibm75n06", "ibm75n07", "ibm75n08", "ibm75n09", "ibm75n10", "ibm75n11", "ibm75n12", "ibm75n13", "ibm76n01",
"ibm76n02", "ibm76n03", "ibm76n04", "ibm76n05", "ibm76n06", "ibm76n07", "ibm77n01", "ibm77n02", "ibm77n03", "ibm77n04", "ibm78n01", "ibm78n02", "ibm79n01", "ibm79n02", "ibm82n01", "ibm82n02", "ibm82n03", "ibm82n04", "ibm82n08", "ibm83n01", "ibm83n03", "ibm83n04", "ibm83n05", "ibm83n06",
// No idea what this is
"misc/432gewf", "ibm28an01",
};
TestFiles(GetXmlFilesStartingWith("ibm/not-wf/"), false, exclude);
}
StringBuilder errorOutput;
void TestFiles(IEnumerable<TestFile> files, bool areWellFormed, string[] exclude)
{
errorOutput = new StringBuilder();
int testsRun = 0;
int ignored = 0;
foreach (TestFile file in files) {
if (exclude.Any(exc => file.Name.Contains(exc))) {
ignored++;
} else {
testsRun++;
TestFile(file, areWellFormed);
}
}
if (testsRun == 0) {
Assert.Fail("Test files not found");
}
if (errorOutput.Length > 0) {
// Can not output ]]> otherwise nuint will crash
Assert.Fail(errorOutput.Replace("]]>", "]]~NUNIT~>").ToString());
}
}
/// <remarks>
/// If using DTD, canonical representation is not checked
/// If using DTD, uknown entiry references are not error
/// </remarks>
bool TestFile(TestFile testFile, bool isWellFormed)
{
bool passed = true;
string content = testFile.Content;
Debug.WriteLine("Testing " + testFile.Name + "...");
AXmlParser parser = new AXmlParser();
bool usingDTD = content.Contains("<!DOCTYPE") && (content.Contains("<!ENTITY") || content.Contains(" SYSTEM "));
if (usingDTD)
parser.UnknownEntityReferenceIsError = false;
AXmlDocument document;
parser.Lock.EnterWriteLock();
try {
document = parser.Parse(content, null);
} finally {
parser.Lock.ExitWriteLock();
}
string printed = PrettyPrintAXmlVisitor.PrettyPrint(document);
if (content != printed) {
errorOutput.AppendFormat("Output of pretty printed XML for \"{0}\" does not match the original.\n", testFile.Name);
errorOutput.AppendFormat("Pretty printed:\n{0}\n", Indent(printed));
passed = false;
}
if (isWellFormed && !usingDTD) {
string canonicalPrint = CanonicalPrintAXmlVisitor.Print(document);
if (testFile.Canonical != null) {
if (testFile.Canonical != canonicalPrint) {
errorOutput.AppendFormat("Canonical XML for \"{0}\" does not match the excpected.\n", testFile.Name);
errorOutput.AppendFormat("Expected:\n{0}\n", Indent(testFile.Canonical));
errorOutput.AppendFormat("Seen:\n{0}\n", Indent(canonicalPrint));
passed = false;
}
} else {
errorOutput.AppendFormat("Can not find canonical output for \"{0}\"", testFile.Name);
errorOutput.AppendFormat("Suggested canonical output:\n{0}\n", Indent(canonicalPrint));
passed = false;
}
}
bool hasErrors = document.SyntaxErrors.FirstOrDefault() != null;
if (isWellFormed && hasErrors) {
errorOutput.AppendFormat("Syntax error(s) in well formed file \"{0}\":\n", testFile.Name);
foreach (var error in document.SyntaxErrors) {
string followingText = content.Substring(error.StartOffset, Math.Min(10, content.Length - error.StartOffset));
errorOutput.AppendFormat("Error ({0}-{1}): {2} (followed by \"{3}\")\n", error.StartOffset, error.EndOffset, error.Message, followingText);
}
passed = false;
}
if (!isWellFormed && !hasErrors) {
errorOutput.AppendFormat("No syntax errors reported for mallformed file \"{0}\"\n", testFile.Name);
passed = false;
}
// Epilog
if (!passed) {
if (testFile.Description != null) {
errorOutput.AppendFormat("Test description:\n{0}\n", Indent(testFile.Description));
}
errorOutput.AppendFormat("File content:\n{0}\n", Indent(content));
errorOutput.AppendLine();
}
return passed;
}
string Indent(string text)
{
return " " + text.TrimEnd().Replace("\n", "\n ");
}
}
}

115
AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/TextReplacementTests.cs

@ -1,115 +0,0 @@ @@ -1,115 +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 ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Xml;
using NUnit.Framework;
namespace ICSharpCode.AvalonEdit.Xml
{
[TestFixture]
public class TextReplacementTests
{
#region Test Data
string initialDocumentText = @"<UserControl x:Class='ICSharpCode.Profiler.Controls.TimeLineCell'
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Grid>
</Grid>
</UserControl>";
string finalDocumentText = @"<UserControl x:Class='ICSharpCode.Profiler.Controls.TimeLineCell'
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height='20' />
<RowDefinition Height='20' />
<RowDefinition Height='Auto' />
</Grid.RowDefinitions>
<StackPanel Orientation='Horizontal'>
<TextBlock Text='Test' />
</StackPanel>
<local:TimeLineControl x:Name='t1' Grid.Row='1' />
<TextBlock Grid.Row='2' Text='Test' />
</Grid>
</UserControl>";
int offset = @"<UserControl x:Class='ICSharpCode.Profiler.Controls.TimeLineCell'
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
".Length;
string original = @" <Grid>
</Grid>";
string replacement = @" <Grid>
<Grid.RowDefinitions>
<RowDefinition Height='20' />
<RowDefinition Height='20' />
<RowDefinition Height='Auto' />
</Grid.RowDefinitions>
<StackPanel Orientation='Horizontal'>
<TextBlock Text='Test' />
</StackPanel>
<local:TimeLineControl x:Name='t1' Grid.Row='1' />
<TextBlock Grid.Row='2' Text='Test' />
</Grid>";
#endregion
[Test]
public void ReplacementTest1()
{
/*
* REPRODUCTION STEPS
*
* 1. Run XmlDOM project
* 2. paste text from initialDocumentText (see Test Data region)
* 3. select lines 4 to 6
* 4. replace with replacement (see Test Data region)
* 5. exception thrown:
* ICSharpCode.AvalonEdit.Xml.InternalException : Assertion failed: cached elements must not have zero length
* at ICSharpCode.AvalonEdit.Xml.AXmlParser.Assert(Boolean condition, String message)
* in c:\Projects\SharpDevelop\4.0\SharpDevelop\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\Xml\AXmlParser.cs:line 121
* at ICSharpCode.AvalonEdit.Xml.TagReader.TryReadFromCacheOrNew[T](T& res, Predicate`1 condition)
* in c:\Projects\SharpDevelop\4.0\SharpDevelop\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\Xml\TagReader.cs:line 39
* at ICSharpCode.AvalonEdit.Xml.TagReader.<ReadText>d__12.MoveNext()
* in c:\Projects\SharpDevelop\4.0\SharpDevelop\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\Xml\TagReader.cs:line 456
* at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
* at System.Collections.Generic.List`1.AddRange(IEnumerable`1 collection)
* at ICSharpCode.AvalonEdit.Xml.TagReader.ReadAllTags()
* in c:\Projects\SharpDevelop\4.0\SharpDevelop\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\Xml\TagReader.cs:line 73
* at ICSharpCode.AvalonEdit.Xml.AXmlParser.Parse(String input, IEnumerable`1 changesSinceLastParse)
* in c:\Projects\SharpDevelop\4.0\SharpDevelop\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit\Xml\AXmlParser.cs:line 161
* at ICSharpCode.AvalonEdit.Tests.XmlParser.TextReplacementTests.RunTest()
* in c:\Projects\SharpDevelop\4.0\SharpDevelop\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit.Tests\XmlParser\TextReplacementTests.cs:line 114
* at ICSharpCode.AvalonEdit.Tests.XmlParser.TextReplacementTests.TestMethod(
* ) in c:\Projects\SharpDevelop\4.0\SharpDevelop\src\Libraries\AvalonEdit\ICSharpCode.AvalonEdit.Tests\XmlParser\TextReplacementTests.cs:line 97
* */
Assert.DoesNotThrow(RunTest1);
}
void RunTest1()
{
AXmlParser parser = new AXmlParser();
try {
parser.Lock.EnterWriteLock();
parser.Parse(initialDocumentText, null); // full reparse
IList<DocumentChangeEventArgs> changes = new List<DocumentChangeEventArgs>();
changes.Add(new DocumentChangeEventArgs(offset, original, replacement));
parser.Parse(finalDocumentText, changes);
} finally {
parser.Lock.ExitWriteLock();
}
}
}
}

BIN
AvalonEdit/ICSharpCode.AvalonEdit.Tests/XmlParser/W3C.zip

Binary file not shown.

15
AvalonEdit/ICSharpCode.AvalonEdit.Tests/app.config

@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="NUnit">
<section name="TestRunner"
type="System.Configuration.NameValueSectionHandler" />
</sectionGroup>
</configSections>
<NUnit>
<TestRunner>
<!-- Valid values are STA,MTA. Others ignored. -->
<add key="ApartmentState" value="STA" />
</TestRunner>
</NUnit>
</configuration>

4
AvalonEdit/ICSharpCode.AvalonEdit.Tests/packages.config

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="2.6.3" targetFramework="net45" />
</packages>

19
AvalonEdit/ICSharpCode.AvalonEdit/AvalonEditCommands.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Input;

55
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
@ -11,6 +26,7 @@ using System.Windows.Controls.Primitives; @@ -11,6 +26,7 @@ using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Linq;
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.CodeCompletion
{
@ -165,14 +181,21 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -165,14 +181,21 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
{
base.OnMouseDoubleClick(e);
if (e.ChangedButton == MouseButton.Left) {
e.Handled = true;
RequestInsertion(e);
// only process double clicks on the ListBoxItems, not on the scroll bar
if (ExtensionMethods.VisualAncestorsAndSelf(e.OriginalSource as DependencyObject).TakeWhile(obj => obj != this).Any(obj => obj is ListBoxItem)) {
e.Handled = true;
RequestInsertion(e);
}
}
}
/// <summary>
/// Gets/Sets the selected item.
/// </summary>
/// <remarks>
/// The setter of this property does not scroll to the selected item.
/// You might want to also call <see cref="ScrollIntoView"/>.
/// </remarks>
public ICompletionData SelectedItem {
get {
return (listBox != null ? listBox.SelectedItem : null) as ICompletionData;
@ -180,10 +203,22 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -180,10 +203,22 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
set {
if (listBox == null && value != null)
ApplyTemplate();
listBox.SelectedItem = value;
if (listBox != null) // may still be null if ApplyTemplate fails, or if listBox and value both are null
listBox.SelectedItem = value;
}
}
/// <summary>
/// Scrolls the specified item into view.
/// </summary>
public void ScrollIntoView(ICompletionData item)
{
if (listBox == null)
ApplyTemplate();
if (listBox != null)
listBox.ScrollIntoView(item);
}
/// <summary>
/// Occurs when the SelectedItem property changes.
/// </summary>
@ -324,7 +359,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -324,7 +359,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
// 5 = match start
// 4 = match CamelCase when length of query is 1 or 2 characters
// 3 = match substring case sensitive
// 2 = match sustring
// 2 = match substring
// 1 = match CamelCase
// -1 = no match
if (query == itemText)
@ -361,11 +396,15 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -361,11 +396,15 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
static bool CamelCaseMatch(string text, string query)
{
// We take the first letter of the text regardless of whether or not it's upper case so we match
// against camelCase text as well as PascalCase text ("cct" matches "camelCaseText")
var theFirstLetterOfEachWord = text.Take(1).Concat(text.Skip(1).Where(char.IsUpper));
int i = 0;
foreach (char upper in text.Where(c => char.IsUpper(c))) {
foreach (var letter in theFirstLetterOfEachWord) {
if (i > query.Length - 1)
return true; // return true here for CamelCase partial match ("CQ" matches "CodeQualityAnalysis")
if (char.ToUpper(query[i], CultureInfo.InvariantCulture) != upper)
if (char.ToUpperInvariant(query[i]) != char.ToUpperInvariant(letter))
return false;
i++;
}

2
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionList.xaml

@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" Width="16" Height="16" Margin="0,0,2,0"/>
<ContentControl Content="{Binding Content}"/>
<ContentPresenter Content="{Binding Content}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>

19
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionListBox.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;

22
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindow.cs

@ -1,14 +1,26 @@ @@ -1,14 +1,26 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;

23
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/CompletionWindowBase.cs

@ -1,17 +1,34 @@ @@ -1,17 +1,34 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.AvalonEdit.CodeCompletion
{

25
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/ICompletionData.cs

@ -1,10 +1,29 @@ @@ -1,10 +1,29 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#else
using ICSharpCode.AvalonEdit.Document;
#endif
namespace ICSharpCode.AvalonEdit.CodeCompletion
{

19
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/IOverloadProvider.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.ObjectModel;

23
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
@ -34,14 +49,14 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -34,14 +49,14 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
/// <inheritdoc/>
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
Rect caret = this.TextArea.Caret.CalculateCaretRectangle();
Point pointOnScreen = this.TextArea.TextView.PointToScreen(caret.Location - this.TextArea.TextView.ScrollOffset);
Rect workingArea = System.Windows.Forms.Screen.FromPoint(pointOnScreen.ToSystemDrawing()).WorkingArea.ToWpf().TransformFromDevice(this);
MaxHeight = workingArea.Height;
MaxWidth = Math.Min(workingArea.Width, Math.Max(1000, workingArea.Width * 0.6));
base.OnSourceInitialized(e);
}
/// <summary>

4
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/InsightWindow.xaml

@ -65,8 +65,8 @@ @@ -65,8 +65,8 @@
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="bd"
Background="{TemplateBinding Background}" CornerRadius="2">
<ContentControl Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Content}"/>
<ContentPresenter Margin="{TemplateBinding Padding}"
Content="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">

21
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadInsightWindow.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
@ -37,7 +52,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion @@ -37,7 +52,7 @@ namespace ICSharpCode.AvalonEdit.CodeCompletion
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (!e.Handled && this.Provider.Count > 1) {
if (!e.Handled && this.Provider != null && this.Provider.Count > 1) {
switch (e.Key) {
case Key.Up:
e.Handled = true;

19
AvalonEdit/ICSharpCode.AvalonEdit/CodeCompletion/OverloadViewer.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.ObjectModel;

140
AvalonEdit/ICSharpCode.AvalonEdit/Document/ChangeTrackingCheckpoint.cs

@ -1,140 +0,0 @@ @@ -1,140 +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 ICSharpCode.AvalonEdit.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ICSharpCode.AvalonEdit.Document
{
/// <summary>
/// <para>A checkpoint that allows tracking changes to a TextDocument.</para>
/// <para>
/// Use <see cref="TextDocument.CreateSnapshot(out ChangeTrackingCheckpoint)"/> to create a checkpoint.
/// </para>
/// </summary>
/// <remarks>
/// <para>The <see cref="ChangeTrackingCheckpoint"/> class allows tracking document changes, even from background threads.</para>
/// <para>Once you have two checkpoints, you can call <see cref="ChangeTrackingCheckpoint.GetChangesTo"/> to retrieve the complete list
/// of document changes that happened between those versions of the document.</para>
/// </remarks>
public sealed class ChangeTrackingCheckpoint
{
// Object that is unique per document.
// Used to determine if two checkpoints belong to the same document.
// We don't use a reference to the document itself to allow the GC to reclaim the document memory
// even if there are still references to checkpoints.
readonly object documentIdentifier;
// 'value' is the change from the previous checkpoint to this checkpoint
// TODO: store the change in the older checkpoint instead - if only a reference to the
// newest document version exists, the GC should be able to collect all DocumentChangeEventArgs.
readonly DocumentChangeEventArgs value;
readonly int id;
ChangeTrackingCheckpoint next;
internal ChangeTrackingCheckpoint(object documentIdentifier)
{
this.documentIdentifier = documentIdentifier;
}
internal ChangeTrackingCheckpoint(object documentIdentifier, DocumentChangeEventArgs value, int id)
{
this.documentIdentifier = documentIdentifier;
this.value = value;
this.id = id;
}
internal ChangeTrackingCheckpoint Append(DocumentChangeEventArgs change)
{
Debug.Assert(this.next == null);
this.next = new ChangeTrackingCheckpoint(this.documentIdentifier, change, unchecked( this.id + 1 ));
return this.next;
}
/// <summary>
/// Creates a change tracking checkpoint for the specified document.
/// This method is thread-safe.
/// If you need a ChangeTrackingCheckpoint that's consistent with a snapshot of the document,
/// use <see cref="TextDocument.CreateSnapshot(out ChangeTrackingCheckpoint)"/>.
/// </summary>
public static ChangeTrackingCheckpoint Create(TextDocument document)
{
if (document == null)
throw new ArgumentNullException("document");
return document.CreateChangeTrackingCheckpoint();
}
/// <summary>
/// Gets whether this checkpoint belongs to the same document as the other checkpoint.
/// </summary>
public bool BelongsToSameDocumentAs(ChangeTrackingCheckpoint other)
{
if (other == null)
throw new ArgumentNullException("other");
return documentIdentifier == other.documentIdentifier;
}
/// <summary>
/// Compares the age of this checkpoint to the other checkpoint.
/// </summary>
/// <remarks>This method is thread-safe.</remarks>
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this checkpoint.</exception>
/// <returns>-1 if this checkpoint is older than <paramref name="other"/>.
/// 0 if <c>this</c>==<paramref name="other"/>.
/// 1 if this checkpoint is newer than <paramref name="other"/>.</returns>
public int CompareAge(ChangeTrackingCheckpoint other)
{
if (other == null)
throw new ArgumentNullException("other");
if (other.documentIdentifier != this.documentIdentifier)
throw new ArgumentException("Checkpoints do not belong to the same document.");
// We will allow overflows, but assume that the maximum distance between checkpoints is 2^31-1.
// This is guaranteed on x86 because so many checkpoints don't fit into memory.
return Math.Sign(unchecked( this.id - other.id ));
}
/// <summary>
/// Gets the changes from this checkpoint to the other checkpoint.
/// If 'other' is older than this checkpoint, reverse changes are calculated.
/// </summary>
/// <remarks>This method is thread-safe.</remarks>
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this checkpoint.</exception>
public IEnumerable<DocumentChangeEventArgs> GetChangesTo(ChangeTrackingCheckpoint other)
{
int result = CompareAge(other);
if (result < 0)
return GetForwardChanges(other);
else if (result > 0)
return other.GetForwardChanges(this).Reverse().Select(change => change.Invert());
else
return Empty<DocumentChangeEventArgs>.Array;
}
IEnumerable<DocumentChangeEventArgs> GetForwardChanges(ChangeTrackingCheckpoint other)
{
// Return changes from this(exclusive) to other(inclusive).
ChangeTrackingCheckpoint node = this;
do {
node = node.next;
yield return node.value;
} while (node != other);
}
/// <summary>
/// Calculates where the offset has moved in the other buffer version.
/// </summary>
/// <remarks>This method is thread-safe.</remarks>
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this checkpoint.</exception>
public int MoveOffsetTo(ChangeTrackingCheckpoint other, int oldOffset, AnchorMovementType movement)
{
int offset = oldOffset;
foreach (DocumentChangeEventArgs e in GetChangesTo(other)) {
offset = e.GetNewOffset(offset, movement);
}
return offset;
}
}
}

86
AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentChangeEventArgs.cs

@ -1,8 +1,24 @@ @@ -1,8 +1,24 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.AvalonEdit.Utils;
using System;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.AvalonEdit.Document
{
@ -11,37 +27,8 @@ namespace ICSharpCode.AvalonEdit.Document @@ -11,37 +27,8 @@ namespace ICSharpCode.AvalonEdit.Document
/// This class is thread-safe.
/// </summary>
[Serializable]
public class DocumentChangeEventArgs : EventArgs
public class DocumentChangeEventArgs : TextChangeEventArgs
{
/// <summary>
/// The offset at which the change occurs.
/// </summary>
public int Offset { get; private set; }
/// <summary>
/// The text that was removed.
/// </summary>
public string RemovedText { get; private set; }
/// <summary>
/// The number of characters removed.
/// </summary>
public int RemovalLength {
get { return RemovedText.Length; }
}
/// <summary>
/// The text that was inserted.
/// </summary>
public string InsertedText { get; private set; }
/// <summary>
/// The number of characters inserted.
/// </summary>
public int InsertionLength {
get { return InsertedText.Length; }
}
volatile OffsetChangeMap offsetChangeMap;
/// <summary>
@ -77,7 +64,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -77,7 +64,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Gets the new offset where the specified offset moves after this document change.
/// </summary>
public int GetNewOffset(int offset, AnchorMovementType movementType)
public override int GetNewOffset(int offset, AnchorMovementType movementType = AnchorMovementType.Default)
{
if (offsetChangeMap != null)
return offsetChangeMap.GetNewOffset(offset, movementType);
@ -97,28 +84,33 @@ namespace ICSharpCode.AvalonEdit.Document @@ -97,28 +84,33 @@ namespace ICSharpCode.AvalonEdit.Document
/// Creates a new DocumentChangeEventArgs object.
/// </summary>
public DocumentChangeEventArgs(int offset, string removedText, string insertedText, OffsetChangeMap offsetChangeMap)
: base(offset, removedText, insertedText)
{
SetOffsetChangeMap(offsetChangeMap);
}
/// <summary>
/// Creates a new DocumentChangeEventArgs object.
/// </summary>
public DocumentChangeEventArgs(int offset, ITextSource removedText, ITextSource insertedText, OffsetChangeMap offsetChangeMap)
: base(offset, removedText, insertedText)
{
SetOffsetChangeMap(offsetChangeMap);
}
void SetOffsetChangeMap(OffsetChangeMap offsetChangeMap)
{
ThrowUtil.CheckNotNegative(offset, "offset");
ThrowUtil.CheckNotNull(removedText, "removedText");
ThrowUtil.CheckNotNull(insertedText, "insertedText");
this.Offset = offset;
this.RemovedText = removedText;
this.InsertedText = insertedText;
if (offsetChangeMap != null) {
if (!offsetChangeMap.IsFrozen)
throw new ArgumentException("The OffsetChangeMap must be frozen before it can be used in DocumentChangeEventArgs");
if (!offsetChangeMap.IsValidForDocumentChange(offset, removedText.Length, insertedText.Length))
if (!offsetChangeMap.IsValidForDocumentChange(this.Offset, this.RemovalLength, this.InsertionLength))
throw new ArgumentException("OffsetChangeMap is not valid for this document change", "offsetChangeMap");
this.offsetChangeMap = offsetChangeMap;
}
}
/// <summary>
/// Creates DocumentChangeEventArgs for the reverse change.
/// </summary>
public DocumentChangeEventArgs Invert()
/// <inheritdoc/>
public override TextChangeEventArgs Invert()
{
OffsetChangeMap map = this.OffsetChangeMapOrNull;
if (map != null) {

19
AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentChangeOperation.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;

32
AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLine.cs

@ -1,9 +1,27 @@ @@ -1,9 +1,27 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;
using System.Globalization;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{
@ -22,7 +40,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -22,7 +40,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// and the data structure also updates all offsets in O(lg N) whenever a line is inserted or removed.
/// </para>
/// </remarks>
public sealed partial class DocumentLine : ISegment
public sealed partial class DocumentLine : IDocumentLine
{
#region Constructor
#if DEBUG
@ -221,6 +239,14 @@ namespace ICSharpCode.AvalonEdit.Document @@ -221,6 +239,14 @@ namespace ICSharpCode.AvalonEdit.Document
}
}
}
IDocumentLine IDocumentLine.NextLine {
get { return this.NextLine; }
}
IDocumentLine IDocumentLine.PreviousLine {
get { return this.PreviousLine; }
}
#endregion
#region ToString

19
AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentLineTree.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;

86
AvalonEdit/ICSharpCode.AvalonEdit/Document/DocumentTextWriter.cs

@ -0,0 +1,86 @@ @@ -0,0 +1,86 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
using System.Text;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{
/// <summary>
/// A TextWriter implementation that directly inserts into a document.
/// </summary>
public class DocumentTextWriter : TextWriter
{
readonly IDocument document;
int insertionOffset;
/// <summary>
/// Creates a new DocumentTextWriter that inserts into document, starting at insertionOffset.
/// </summary>
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);
}
/// <summary>
/// Gets/Sets the current insertion offset.
/// </summary>
public int InsertionOffset {
get { return insertionOffset; }
set { insertionOffset = value; }
}
/// <inheritdoc/>
public override void Write(char value)
{
document.Insert(insertionOffset, value.ToString());
insertionOffset++;
}
/// <inheritdoc/>
public override void Write(char[] buffer, int index, int count)
{
document.Insert(insertionOffset, new string(buffer, index, count));
insertionOffset += count;
}
/// <inheritdoc/>
public override void Write(string value)
{
document.Insert(insertionOffset, value);
insertionOffset += value.Length;
}
/// <inheritdoc/>
public override Encoding Encoding {
get { return Encoding.UTF8; }
}
}
}

19
AvalonEdit/ICSharpCode.AvalonEdit/Document/GapTextBuffer.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;

343
AvalonEdit/ICSharpCode.AvalonEdit/Document/IDocument.cs

@ -0,0 +1,343 @@ @@ -0,0 +1,343 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.AvalonEdit.Document
{
#if !NREFACTORY
/// <summary>
/// A document representing a source code file for refactoring.
/// Line and column counting starts at 1.
/// Offset counting starts at 0.
/// </summary>
public interface IDocument : ITextSource, IServiceProvider
{
#if NREFACTORY
/// <summary>
/// Creates an immutable snapshot of this document.
/// </summary>
IDocument CreateDocumentSnapshot();
#endif
/// <summary>
/// Gets/Sets the text of the whole document..
/// </summary>
new string Text { get; set; } // hides ITextSource.Text to add the setter
/// <summary>
/// This event is called directly before a change is applied to the document.
/// </summary>
/// <remarks>
/// It is invalid to modify the document within this event handler.
/// Aborting the change (by throwing an exception) is likely to cause corruption of data structures
/// that listen to the Changing and Changed events.
/// </remarks>
event EventHandler<TextChangeEventArgs> TextChanging;
/// <summary>
/// This event is called directly after a change is applied to the document.
/// </summary>
/// <remarks>
/// It is invalid to modify the document within this event handler.
/// Aborting the event handler (by throwing an exception) is likely to cause corruption of data structures
/// that listen to the Changing and Changed events.
/// </remarks>
event EventHandler<TextChangeEventArgs> TextChanged;
/// <summary>
/// This event is called after a group of changes is completed.
/// </summary>
/// <seealso cref="EndUndoableAction"/>
event EventHandler ChangeCompleted;
/// <summary>
/// Gets the number of lines in the document.
/// </summary>
int LineCount { get; }
/// <summary>
/// Gets the document line with the specified number.
/// </summary>
/// <param name="lineNumber">The number of the line to retrieve. The first line has number 1.</param>
IDocumentLine GetLineByNumber(int lineNumber);
/// <summary>
/// Gets the document line that contains the specified offset.
/// </summary>
IDocumentLine GetLineByOffset(int offset);
/// <summary>
/// Gets the offset from a text location.
/// </summary>
/// <seealso cref="GetLocation"/>
int GetOffset(int line, int column);
/// <summary>
/// Gets the offset from a text location.
/// </summary>
/// <seealso cref="GetLocation"/>
int GetOffset(TextLocation location);
/// <summary>
/// Gets the location from an offset.
/// </summary>
/// <seealso cref="GetOffset(TextLocation)"/>
TextLocation GetLocation(int offset);
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <remarks>
/// Anchors positioned exactly at the insertion offset will move according to their movement type.
/// For AnchorMovementType.Default, they will move behind the inserted text.
/// The caret will also move behind the inserted text.
/// </remarks>
void Insert(int offset, string text);
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <remarks>
/// Anchors positioned exactly at the insertion offset will move according to their movement type.
/// For AnchorMovementType.Default, they will move behind the inserted text.
/// The caret will also move behind the inserted text.
/// </remarks>
void Insert(int offset, ITextSource text);
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <param name="defaultAnchorMovementType">
/// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type.
/// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter.
/// The caret will also move according to the <paramref name="defaultAnchorMovementType"/> parameter.
/// </param>
void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType);
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <param name="defaultAnchorMovementType">
/// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type.
/// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter.
/// The caret will also move according to the <paramref name="defaultAnchorMovementType"/> parameter.
/// </param>
void Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType);
/// <summary>
/// Removes text.
/// </summary>
/// <param name="offset">Starting offset of the text to be removed.</param>
/// <param name="length">Length of the text to be removed.</param>
void Remove(int offset, int length);
/// <summary>
/// Replaces text.
/// </summary>
/// <param name="offset">The starting offset of the text to be replaced.</param>
/// <param name="length">The length of the text to be replaced.</param>
/// <param name="newText">The new text.</param>
void Replace(int offset, int length, string newText);
/// <summary>
/// Replaces text.
/// </summary>
/// <param name="offset">The starting offset of the text to be replaced.</param>
/// <param name="length">The length of the text to be replaced.</param>
/// <param name="newText">The new text.</param>
void Replace(int offset, int length, ITextSource newText);
/// <summary>
/// Make the document combine the following actions into a single
/// action for undo purposes.
/// </summary>
void StartUndoableAction();
/// <summary>
/// Ends the undoable action started with <see cref="StartUndoableAction"/>.
/// </summary>
void EndUndoableAction();
/// <summary>
/// Creates an undo group. Dispose the returned value to close the undo group.
/// </summary>
/// <returns>An object that closes the undo group when Dispose() is called.</returns>
IDisposable OpenUndoGroup();
/// <summary>
/// Creates a new <see cref="ITextAnchor"/> at the specified offset.
/// </summary>
/// <inheritdoc cref="ITextAnchor" select="remarks|example"/>
ITextAnchor CreateAnchor(int offset);
/// <summary>
/// Gets the name of the file the document is stored in.
/// Could also be a non-existent dummy file name or null if no name has been set.
/// </summary>
string FileName { get; }
/// <summary>
/// Fired when the file name of the document changes.
/// </summary>
event EventHandler FileNameChanged;
}
/// <summary>
/// A line inside a <see cref="IDocument"/>.
/// </summary>
public interface IDocumentLine : ISegment
{
/// <summary>
/// Gets the length of this line, including the line delimiter.
/// </summary>
int TotalLength { get; }
/// <summary>
/// Gets the length of the line terminator.
/// Returns 1 or 2; or 0 at the end of the document.
/// </summary>
int DelimiterLength { get; }
/// <summary>
/// Gets the number of this line.
/// The first line has the number 1.
/// </summary>
int LineNumber { get; }
/// <summary>
/// Gets the previous line. Returns null if this is the first line in the document.
/// </summary>
IDocumentLine PreviousLine { get; }
/// <summary>
/// Gets the next line. Returns null if this is the last line in the document.
/// </summary>
IDocumentLine NextLine { get; }
/// <summary>
/// Gets whether the line was deleted.
/// </summary>
bool IsDeleted { get; }
}
/// <summary>
/// Describes a change of the document text.
/// This class is thread-safe.
/// </summary>
[Serializable]
public class TextChangeEventArgs : EventArgs
{
readonly int offset;
readonly ITextSource removedText;
readonly ITextSource insertedText;
/// <summary>
/// The offset at which the change occurs.
/// </summary>
public int Offset {
get { return offset; }
}
/// <summary>
/// The text that was removed.
/// </summary>
public ITextSource RemovedText {
get { return removedText; }
}
/// <summary>
/// The number of characters removed.
/// </summary>
public int RemovalLength {
get { return removedText.TextLength; }
}
/// <summary>
/// The text that was inserted.
/// </summary>
public ITextSource InsertedText {
get { return insertedText; }
}
/// <summary>
/// The number of characters inserted.
/// </summary>
public int InsertionLength {
get { return insertedText.TextLength; }
}
/// <summary>
/// Creates a new TextChangeEventArgs object.
/// </summary>
public TextChangeEventArgs(int offset, string removedText, string insertedText)
{
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", offset, "offset must not be negative");
this.offset = offset;
this.removedText = removedText != null ? new StringTextSource(removedText) : StringTextSource.Empty;
this.insertedText = insertedText != null ? new StringTextSource(insertedText) : StringTextSource.Empty;
}
/// <summary>
/// Creates a new TextChangeEventArgs object.
/// </summary>
public TextChangeEventArgs(int offset, ITextSource removedText, ITextSource insertedText)
{
if (offset < 0)
throw new ArgumentOutOfRangeException("offset", offset, "offset must not be negative");
this.offset = offset;
this.removedText = removedText ?? StringTextSource.Empty;
this.insertedText = insertedText ?? StringTextSource.Empty;
}
/// <summary>
/// Gets the new offset where the specified offset moves after this document change.
/// </summary>
public virtual int GetNewOffset(int offset, AnchorMovementType movementType = AnchorMovementType.Default)
{
if (offset >= this.Offset && offset <= this.Offset + this.RemovalLength) {
if (movementType == AnchorMovementType.BeforeInsertion)
return this.Offset;
else
return this.Offset + this.InsertionLength;
} else if (offset > this.Offset) {
return offset + this.InsertionLength - this.RemovalLength;
} else {
return offset;
}
}
/// <summary>
/// Creates TextChangeEventArgs for the reverse change.
/// </summary>
public virtual TextChangeEventArgs Invert()
{
return new TextChangeEventArgs(offset, insertedText, removedText);
}
}
#endif
}

26
AvalonEdit/ICSharpCode.AvalonEdit/Document/ILineTracker.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
@ -51,5 +66,12 @@ namespace ICSharpCode.AvalonEdit.Document @@ -51,5 +66,12 @@ namespace ICSharpCode.AvalonEdit.Document
/// throw away their data and rebuild the document.
/// </summary>
void RebuildDocument();
/// <summary>
/// Notifies the line tracker that a document change (a single change, not a change group) has completed.
/// This method gets called after the change has been performed, but before the <see cref="TextDocument.Changed"/> event
/// is raised.
/// </summary>
void ChangeComplete(DocumentChangeEventArgs e);
}
}

142
AvalonEdit/ICSharpCode.AvalonEdit/Document/ITextAnchor.cs

@ -0,0 +1,142 @@ @@ -0,0 +1,142 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.NRefactory;
namespace ICSharpCode.AvalonEdit.Document
{
#if !NREFACTORY
/// <summary>
/// The TextAnchor class references an offset (a position between two characters).
/// It automatically updates the offset when text is inserted/removed in front of the anchor.
/// </summary>
/// <remarks>
/// <para>Use the <see cref="ITextAnchor.Offset"/> property to get the offset from a text anchor.
/// Use the <see cref="IDocument.CreateAnchor"/> method to create an anchor from an offset.
/// </para>
/// <para>
/// The document will automatically update all text anchors; and because it uses weak references to do so,
/// the garbage collector can simply collect the anchor object when you don't need it anymore.
/// </para>
/// <para>Moreover, the document is able to efficiently update a large number of anchors without having to look
/// at each anchor object individually. Updating the offsets of all anchors usually only takes time logarithmic
/// to the number of anchors. Retrieving the <see cref="ITextAnchor.Offset"/> property also runs in O(lg N).</para>
/// </remarks>
/// <example>
/// Usage:
/// <code>TextAnchor anchor = document.CreateAnchor(offset);
/// ChangeMyDocument();
/// int newOffset = anchor.Offset;
/// </code>
/// </example>
public interface ITextAnchor
{
/// <summary>
/// Gets the text location of this anchor.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
TextLocation Location { get; }
/// <summary>
/// Gets the offset of the text anchor.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
int Offset { get; }
/// <summary>
/// Controls how the anchor moves.
/// </summary>
/// <remarks>Anchor movement is ambiguous if text is inserted exactly at the anchor's location.
/// Does the anchor stay before the inserted text, or does it move after it?
/// The property <see cref="MovementType"/> will be used to determine which of these two options the anchor will choose.
/// The default value is <see cref="AnchorMovementType.Default"/>.</remarks>
AnchorMovementType MovementType { get; set; }
/// <summary>
/// <para>
/// Specifies whether the anchor survives deletion of the text containing it.
/// </para><para>
/// <c>false</c>: The anchor is deleted when the a selection that includes the anchor is deleted.
/// <c>true</c>: The anchor is not deleted.
/// </para>
/// </summary>
/// <remarks><inheritdoc cref="IsDeleted" /></remarks>
bool SurviveDeletion { get; set; }
/// <summary>
/// Gets whether the anchor was deleted.
/// </summary>
/// <remarks>
/// <para>When a piece of text containing an anchor is removed, then that anchor will be deleted.
/// First, the <see cref="IsDeleted"/> property is set to true on all deleted anchors,
/// then the <see cref="Deleted"/> events are raised.
/// You cannot retrieve the offset from an anchor that has been deleted.</para>
/// <para>This deletion behavior might be useful when using anchors for building a bookmark feature,
/// but in other cases you want to still be able to use the anchor. For those cases, set <c><see cref="SurviveDeletion"/> = true</c>.</para>
/// </remarks>
bool IsDeleted { get; }
/// <summary>
/// Occurs after the anchor was deleted.
/// </summary>
/// <remarks>
/// <inheritdoc cref="IsDeleted" />
/// <para>Due to the 'weak reference' nature of text anchors, you will receive
/// the Deleted event only while your code holds a reference to the TextAnchor object.
/// </para>
/// </remarks>
event EventHandler Deleted;
/// <summary>
/// Gets the line number of the anchor.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
int Line { get; }
/// <summary>
/// Gets the column number of this anchor.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when trying to get the Offset from a deleted anchor.</exception>
int Column { get; }
}
/// <summary>
/// Defines how a text anchor moves.
/// </summary>
public enum AnchorMovementType
{
/// <summary>
/// When text is inserted at the anchor position, the type of the insertion
/// determines where the caret moves to. For normal insertions, the anchor will move
/// after the inserted text.
/// </summary>
Default,
/// <summary>
/// Behaves like a start marker - when text is inserted at the anchor position, the anchor will stay
/// before the inserted text.
/// </summary>
BeforeInsertion,
/// <summary>
/// Behave like an end marker - when text is insered at the anchor position, the anchor will move
/// after the inserted text.
/// </summary>
AfterInsertion
}
#endif
}

389
AvalonEdit/ICSharpCode.AvalonEdit/Document/ITextSource.cs

@ -1,29 +1,61 @@ @@ -1,29 +1,61 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.AvalonEdit.Utils;
using System.Collections.Generic;
using System;
using System.IO;
namespace ICSharpCode.AvalonEdit.Document
{
#if !NREFACTORY
/// <summary>
/// Interface for read-only access to a text source.
/// A read-only view on a (potentially mutable) text source.
/// The IDocument interface derives from this interface.
/// </summary>
/// <seealso cref="TextDocument"/>
/// <seealso cref="StringTextSource"/>
public interface ITextSource
{
/// <summary>
/// Gets the whole text as string.
/// Gets a version identifier for this text source.
/// Returns null for unversioned text sources.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
string Text { get; }
ITextSourceVersion Version { get; }
/// <summary>
/// Creates an immutable snapshot of this text source.
/// Unlike all other methods in this interface, this method is thread-safe.
/// </summary>
ITextSource CreateSnapshot();
/// <summary>
/// Creates an immutable snapshot of a part of this text source.
/// Unlike all other methods in this interface, this method is thread-safe.
/// </summary>
ITextSource CreateSnapshot(int offset, int length);
/// <summary>
/// Is raised when the Text property changes.
/// Creates a new TextReader to read from this text source.
/// </summary>
event EventHandler TextChanged;
TextReader CreateReader();
/// <summary>
/// Creates a new TextReader to read from this text source.
/// </summary>
TextReader CreateReader(int offset, int length);
/// <summary>
/// Gets the total text length.
@ -33,6 +65,12 @@ namespace ICSharpCode.AvalonEdit.Document @@ -33,6 +65,12 @@ namespace ICSharpCode.AvalonEdit.Document
/// it doesn't require creating a String object.</remarks>
int TextLength { get; }
/// <summary>
/// Gets the whole text as string.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
string Text { get; }
/// <summary>
/// Gets a character at the specified position in the document.
/// </summary>
@ -40,18 +78,9 @@ namespace ICSharpCode.AvalonEdit.Document @@ -40,18 +78,9 @@ namespace ICSharpCode.AvalonEdit.Document
/// <exception cref="ArgumentOutOfRangeException">Offset is outside the valid range (0 to TextLength-1).</exception>
/// <returns>The character at the specified position.</returns>
/// <remarks>This is the same as Text[offset], but is more efficient because
/// it doesn't require creating a String object.</remarks>
/// it doesn't require creating a String object.</remarks>
char GetCharAt(int offset);
/// <summary>
/// Gets the index of the first occurrence of any character in the specified array.
/// </summary>
/// <param name="anyOf"></param>
/// <param name="startIndex">Start index of the search.</param>
/// <param name="count">Length of the area to search.</param>
/// <returns>The first index where any character was found; or -1 if no occurrence was found.</returns>
int IndexOfAny(char[] anyOf, int startIndex, int count);
/// <summary>
/// Retrieves the text for a portion of the document.
/// </summary>
@ -61,121 +90,149 @@ namespace ICSharpCode.AvalonEdit.Document @@ -61,121 +90,149 @@ namespace ICSharpCode.AvalonEdit.Document
string GetText(int offset, int length);
/// <summary>
/// Creates a snapshot of the current text.
/// Retrieves the text for a portion of the document.
/// </summary>
/// <remarks>
/// This method is generally not thread-safe when called on a mutable text buffer, but the resulting text buffer is immutable and thread-safe.
/// However, some implementing classes may provide additional thread-safety guarantees, see <see cref="TextDocument.CreateSnapshot()">TextDocument.CreateSnapshot</see>.
/// </remarks>
ITextSource CreateSnapshot();
/// <exception cref="ArgumentOutOfRangeException">offset or length is outside the valid range.</exception>
string GetText(ISegment segment);
/// <summary>
/// Creates a snapshot of a part of the current text.
/// Writes the text from this document into the TextWriter.
/// </summary>
/// <remarks>
/// This method is generally not thread-safe when called on a mutable text buffer, but the resulting text buffer is immutable and thread-safe.
/// However, some implementing classes may provide additional thread-safety guarantees, see <see cref="TextDocument.CreateSnapshot()">TextDocument.CreateSnapshot</see>.
/// </remarks>
ITextSource CreateSnapshot(int offset, int length);
void WriteTextTo(TextWriter writer);
/// <summary>
/// Creates a text reader.
/// If the text is changed while a reader is active, the reader will continue to read from the old text version.
/// Writes the text from this document into the TextWriter.
/// </summary>
TextReader CreateReader();
}
/// <summary>
/// Implements the ITextSource interface by wrapping another TextSource
/// and viewing only a part of the text.
/// </summary>
[Obsolete("This class will be removed in a future version of AvalonEdit")]
public sealed class TextSourceView : ITextSource
{
readonly ITextSource baseTextSource;
readonly ISegment viewedSegment;
void WriteTextTo(TextWriter writer, int offset, int length);
/// <summary>
/// Creates a new TextSourceView object.
/// Gets the index of the first occurrence of the character in the specified array.
/// </summary>
/// <param name="baseTextSource">The base text source.</param>
/// <param name="viewedSegment">A text segment from the base text source</param>
public TextSourceView(ITextSource baseTextSource, ISegment viewedSegment)
{
if (baseTextSource == null)
throw new ArgumentNullException("baseTextSource");
if (viewedSegment == null)
throw new ArgumentNullException("viewedSegment");
this.baseTextSource = baseTextSource;
this.viewedSegment = viewedSegment;
}
/// <param name="c">Character to search for</param>
/// <param name="startIndex">Start index of the area to search.</param>
/// <param name="count">Length of the area to search.</param>
/// <returns>The first index where the character was found; or -1 if no occurrence was found.</returns>
int IndexOf(char c, int startIndex, int count);
/// <inheritdoc/>
public event EventHandler TextChanged {
add { baseTextSource.TextChanged += value; }
remove { baseTextSource.TextChanged -= value; }
}
/// <summary>
/// Gets the index of the first occurrence of any character in the specified array.
/// </summary>
/// <param name="anyOf">Characters to search for</param>
/// <param name="startIndex">Start index of the area to search.</param>
/// <param name="count">Length of the area to search.</param>
/// <returns>The first index where any character was found; or -1 if no occurrence was found.</returns>
int IndexOfAny(char[] anyOf, int startIndex, int count);
/// <inheritdoc/>
public string Text {
get {
return baseTextSource.GetText(viewedSegment.Offset, viewedSegment.Length);
}
}
/// <summary>
/// Gets the index of the first occurrence of the specified search text in this text source.
/// </summary>
/// <param name="searchText">The search text</param>
/// <param name="startIndex">Start index of the area to search.</param>
/// <param name="count">Length of the area to search.</param>
/// <param name="comparisonType">String comparison to use.</param>
/// <returns>The first index where the search term was found; or -1 if no occurrence was found.</returns>
int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType);
/// <inheritdoc/>
public int TextLength {
get { return viewedSegment.Length; }
}
/// <summary>
/// Gets the index of the last occurrence of the specified character in this text source.
/// </summary>
/// <param name="c">The search character</param>
/// <param name="startIndex">Start index of the area to search.</param>
/// <param name="count">Length of the area to search.</param>
/// <returns>The last index where the search term was found; or -1 if no occurrence was found.</returns>
/// <remarks>The search proceeds backwards from (startIndex+count) to startIndex.
/// This is different than the meaning of the parameters on string.LastIndexOf!</remarks>
int LastIndexOf(char c, int startIndex, int count);
/// <inheritdoc/>
public char GetCharAt(int offset)
{
return baseTextSource.GetCharAt(viewedSegment.Offset + offset);
}
/// <summary>
/// Gets the index of the last occurrence of the specified search text in this text source.
/// </summary>
/// <param name="searchText">The search text</param>
/// <param name="startIndex">Start index of the area to search.</param>
/// <param name="count">Length of the area to search.</param>
/// <param name="comparisonType">String comparison to use.</param>
/// <returns>The last index where the search term was found; or -1 if no occurrence was found.</returns>
/// <remarks>The search proceeds backwards from (startIndex+count) to startIndex.
/// This is different than the meaning of the parameters on string.LastIndexOf!</remarks>
int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType);
/// <inheritdoc/>
public string GetText(int offset, int length)
{
return baseTextSource.GetText(viewedSegment.Offset + offset, length);
}
/* What about:
void Insert (int offset, string value);
void Remove (int offset, int count);
void Remove (ISegment segment);
/// <inheritdoc/>
public ITextSource CreateSnapshot()
{
return baseTextSource.CreateSnapshot(viewedSegment.Offset, viewedSegment.Length);
}
void Replace (int offset, int count, string value);
/// <inheritdoc/>
public ITextSource CreateSnapshot(int offset, int length)
{
return baseTextSource.CreateSnapshot(viewedSegment.Offset + offset, length);
}
Or more search operations:
/// <inheritdoc/>
public TextReader CreateReader()
{
return CreateSnapshot().CreateReader();
}
IEnumerable<int> SearchForward (string pattern, int startIndex);
IEnumerable<int> SearchForwardIgnoreCase (string pattern, int startIndex);
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
int offset = viewedSegment.Offset;
int result = baseTextSource.IndexOfAny(anyOf, startIndex + offset, count);
return result >= 0 ? result - offset : result;
}
IEnumerable<int> SearchBackward (string pattern, int startIndex);
IEnumerable<int> SearchBackwardIgnoreCase (string pattern, int startIndex);
*/
}
/// <summary>
/// Represents a version identifier for a text source.
/// </summary>
/// <remarks>
/// Verions can be used to efficiently detect whether a document has changed and needs reparsing;
/// or even to implement incremental parsers.
/// It is a separate class from ITextSource to allow the GC to collect the text source while
/// the version checkpoint is still in use.
/// </remarks>
public interface ITextSourceVersion
{
/// <summary>
/// Gets whether this checkpoint belongs to the same document as the other checkpoint.
/// </summary>
/// <remarks>
/// Returns false when given <c>null</c>.
/// </remarks>
bool BelongsToSameDocumentAs(ITextSourceVersion other);
/// <summary>
/// Compares the age of this checkpoint to the other checkpoint.
/// </summary>
/// <remarks>This method is thread-safe.</remarks>
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this version.</exception>
/// <returns>-1 if this version is older than <paramref name="other"/>.
/// 0 if <c>this</c> version instance represents the same version as <paramref name="other"/>.
/// 1 if this version is newer than <paramref name="other"/>.</returns>
int CompareAge(ITextSourceVersion other);
/// <summary>
/// Gets the changes from this checkpoint to the other checkpoint.
/// If 'other' is older than this checkpoint, reverse changes are calculated.
/// </summary>
/// <remarks>This method is thread-safe.</remarks>
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this checkpoint.</exception>
IEnumerable<TextChangeEventArgs> GetChangesTo(ITextSourceVersion other);
/// <summary>
/// Calculates where the offset has moved in the other buffer version.
/// </summary>
/// <exception cref="ArgumentException">Raised if 'other' belongs to a different document than this checkpoint.</exception>
int MoveOffsetTo(ITextSourceVersion other, int oldOffset, AnchorMovementType movement = AnchorMovementType.Default);
}
/// <summary>
/// Implements the ITextSource interface using a string.
/// </summary>
public sealed class StringTextSource : ITextSource
[Serializable]
public class StringTextSource : ITextSource
{
/// <summary>
/// Gets a text source containing the empty string.
/// </summary>
public static readonly StringTextSource Empty = new StringTextSource(string.Empty);
readonly string text;
readonly ITextSourceVersion version;
/// <summary>
/// Creates a new StringTextSource.
/// Creates a new StringTextSource with the given text.
/// </summary>
public StringTextSource(string text)
{
@ -184,12 +241,20 @@ namespace ICSharpCode.AvalonEdit.Document @@ -184,12 +241,20 @@ namespace ICSharpCode.AvalonEdit.Document
this.text = text;
}
// Text can never change
event EventHandler ITextSource.TextChanged { add {} remove {} }
/// <summary>
/// Creates a new StringTextSource with the given text.
/// </summary>
public StringTextSource(string text, ITextSourceVersion version)
{
if (text == null)
throw new ArgumentNullException("text");
this.text = text;
this.version = version;
}
/// <inheritdoc/>
public string Text {
get { return text; }
public ITextSourceVersion Version {
get { return version; }
}
/// <inheritdoc/>
@ -198,123 +263,95 @@ namespace ICSharpCode.AvalonEdit.Document @@ -198,123 +263,95 @@ namespace ICSharpCode.AvalonEdit.Document
}
/// <inheritdoc/>
public char GetCharAt(int offset)
{
// GetCharAt must throw ArgumentOutOfRangeException, not IndexOutOfRangeException
if (offset < 0 || offset >= text.Length)
throw new ArgumentOutOfRangeException("offset", offset, "offset must be between 0 and " + (text.Length - 1));
return text[offset];
public string Text {
get { return text; }
}
/// <inheritdoc/>
public string GetText(int offset, int length)
public ITextSource CreateSnapshot()
{
return text.Substring(offset, length);
return this; // StringTextSource is immutable
}
/// <inheritdoc/>
public TextReader CreateReader()
public ITextSource CreateSnapshot(int offset, int length)
{
return new StringReader(text);
return new StringTextSource(text.Substring(offset, length));
}
/// <inheritdoc/>
public ITextSource CreateSnapshot()
public TextReader CreateReader()
{
return this; // StringTextSource already is immutable
return new StringReader(text);
}
/// <inheritdoc/>
public ITextSource CreateSnapshot(int offset, int length)
public TextReader CreateReader(int offset, int length)
{
return new StringTextSource(text.Substring(offset, length));
return new StringReader(text.Substring(offset, length));
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
return text.IndexOfAny(anyOf, startIndex, count);
}
}
/// <summary>
/// Implements the ITextSource interface using a rope.
/// </summary>
public sealed class RopeTextSource : ITextSource
{
readonly Rope<char> rope;
/// <summary>
/// Creates a new RopeTextSource.
/// </summary>
public RopeTextSource(Rope<char> rope)
public void WriteTextTo(TextWriter writer)
{
if (rope == null)
throw new ArgumentNullException("rope");
this.rope = rope;
writer.Write(text);
}
/// <summary>
/// Returns a clone of the rope used for this text source.
/// </summary>
/// <remarks>
/// RopeTextSource only publishes a copy of the contained rope to ensure that the underlying rope cannot be modified.
/// Unless the creator of the RopeTextSource still has a reference on the rope, RopeTextSource is immutable.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Not a property because it creates a clone")]
public Rope<char> GetRope()
/// <inheritdoc/>
public void WriteTextTo(TextWriter writer, int offset, int length)
{
return rope.Clone();
writer.Write(text.Substring(offset, length));
}
// Change event is not supported
event EventHandler ITextSource.TextChanged { add {} remove {} }
/// <inheritdoc/>
public string Text {
get { return rope.ToString(); }
public char GetCharAt(int offset)
{
return text[offset];
}
/// <inheritdoc/>
public int TextLength {
get { return rope.Length; }
public string GetText(int offset, int length)
{
return text.Substring(offset, length);
}
/// <inheritdoc/>
public char GetCharAt(int offset)
public string GetText(ISegment segment)
{
return rope[offset];
if (segment == null)
throw new ArgumentNullException("segment");
return text.Substring(segment.Offset, segment.Length);
}
/// <inheritdoc/>
public string GetText(int offset, int length)
public int IndexOf(char c, int startIndex, int count)
{
return rope.ToString(offset, length);
return text.IndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public TextReader CreateReader()
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
return new RopeTextReader(rope);
return text.IndexOfAny(anyOf, startIndex, count);
}
/// <inheritdoc/>
public ITextSource CreateSnapshot()
public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{
// we clone the underlying rope because the creator of the RopeTextSource might be modifying it
return new RopeTextSource(rope.Clone());
return text.IndexOf(searchText, startIndex, count, comparisonType);
}
/// <inheritdoc/>
public ITextSource CreateSnapshot(int offset, int length)
public int LastIndexOf(char c, int startIndex, int count)
{
return new RopeTextSource(rope.GetRange(offset, length));
return text.LastIndexOf(c, startIndex + count - 1, count);
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{
return rope.IndexOfAny(anyOf, startIndex, count);
return text.LastIndexOf(searchText, startIndex + count - 1, count, comparisonType);
}
}
#endif
}

19
AvalonEdit/ICSharpCode.AvalonEdit/Document/IUndoableOperation.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;

46
AvalonEdit/ICSharpCode.AvalonEdit/Document/LineManager.cs

@ -1,11 +1,26 @@ @@ -1,11 +1,26 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.AvalonEdit.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.AvalonEdit.Document
{
@ -89,6 +104,13 @@ namespace ICSharpCode.AvalonEdit.Document @@ -89,6 +104,13 @@ namespace ICSharpCode.AvalonEdit.Document
{
// keep the first document line
DocumentLine ls = documentLineTree.GetByNumber(1);
// but mark all other lines as deleted, and detach them from the other nodes
for (DocumentLine line = ls.NextLine; line != null; line = line.NextLine) {
line.isDeleted = true;
line.parent = line.left = line.right = null;
}
// Reset the first line to detach it from the deleted lines
ls.ResetLine();
SimpleSegment ds = NewLineFinder.NextNewLine(document, 0);
List<DocumentLine> lines = new List<DocumentLine>();
int lastDelimiterEnd = 0;
@ -101,7 +123,6 @@ namespace ICSharpCode.AvalonEdit.Document @@ -101,7 +123,6 @@ namespace ICSharpCode.AvalonEdit.Document
ls = new DocumentLine(document);
ds = NewLineFinder.NextNewLine(document, lastDelimiterEnd);
}
ls.ResetLine();
ls.TotalLength = document.TextLength - lastDelimiterEnd;
lines.Add(ls);
documentLineTree.RebuildTree(lines);
@ -181,7 +202,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -181,7 +202,7 @@ namespace ICSharpCode.AvalonEdit.Document
#endregion
#region Insert
public void Insert(int offset, string text)
public void Insert(int offset, ITextSource text)
{
DocumentLine line = documentLineTree.GetByOffset(offset);
int lineOffset = line.Offset;
@ -202,7 +223,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -202,7 +223,7 @@ namespace ICSharpCode.AvalonEdit.Document
if (ds == SimpleSegment.Invalid) {
// no newline is being inserted, all text is inserted in a single line
//line.InsertedLinePart(offset - line.Offset, text.Length);
SetLineLength(line, line.TotalLength + text.Length);
SetLineLength(line, line.TotalLength + text.TextLength);
return;
}
//DocumentLine firstLine = line;
@ -224,9 +245,9 @@ namespace ICSharpCode.AvalonEdit.Document @@ -224,9 +245,9 @@ namespace ICSharpCode.AvalonEdit.Document
}
//firstLine.SplitTo(line);
// insert rest after last delimiter
if (lastDelimiterEnd != text.Length) {
if (lastDelimiterEnd != text.TextLength) {
//line.InsertedLinePart(0, text.Length - lastDelimiterEnd);
SetLineLength(line, line.TotalLength + text.Length - lastDelimiterEnd);
SetLineLength(line, line.TotalLength + text.TextLength - lastDelimiterEnd);
}
}
@ -284,5 +305,14 @@ namespace ICSharpCode.AvalonEdit.Document @@ -284,5 +305,14 @@ namespace ICSharpCode.AvalonEdit.Document
return line;
}
#endregion
#region ChangeComplete
public void ChangeComplete(DocumentChangeEventArgs e)
{
foreach (ILineTracker lt in lineTrackers) {
lt.ChangeComplete(e);
}
}
#endregion
}
}

19
AvalonEdit/ICSharpCode.AvalonEdit/Document/LineNode.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;

28
AvalonEdit/ICSharpCode.AvalonEdit/Document/NewLineFinder.cs

@ -1,10 +1,26 @@ @@ -1,10 +1,26 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{
@ -118,9 +134,9 @@ namespace ICSharpCode.AvalonEdit.Document @@ -118,9 +134,9 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Gets the newline sequence used in the document at the specified line.
/// </summary>
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

29
AvalonEdit/ICSharpCode.AvalonEdit/Document/OffsetChangeMap.cs

@ -1,12 +1,29 @@ @@ -1,12 +1,29 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{
@ -18,7 +35,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -18,7 +35,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Normal replace.
/// Anchors in front of the replaced region will stay in front, anchors after the replaced region will stay after.
/// Anchors in the middle of the removed region will be deleted. Ifthey survive deletion,
/// Anchors in the middle of the removed region will be deleted. If they survive deletion,
/// they move depending on their AnchorMovementType.
/// </summary>
/// <remarks>
@ -108,7 +125,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -108,7 +125,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Gets the new offset where the specified offset moves after this document change.
/// </summary>
public int GetNewOffset(int offset, AnchorMovementType movementType)
public int GetNewOffset(int offset, AnchorMovementType movementType = AnchorMovementType.Default)
{
IList<OffsetChangeMapEntry> items = this.Items;
int count = items.Count;
@ -255,7 +272,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -255,7 +272,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Gets the new offset where the specified offset moves after this document change.
/// </summary>
public int GetNewOffset(int oldOffset, AnchorMovementType movementType)
public int GetNewOffset(int oldOffset, AnchorMovementType movementType = AnchorMovementType.Default)
{
int insertionLength = this.InsertionLength;
int removalLength = this.RemovalLength;

169
AvalonEdit/ICSharpCode.AvalonEdit/Document/RopeTextSource.cs

@ -0,0 +1,169 @@ @@ -0,0 +1,169 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{
/// <summary>
/// Implements the ITextSource interface using a rope.
/// </summary>
[Serializable]
public sealed class RopeTextSource : ITextSource
{
readonly Rope<char> rope;
readonly ITextSourceVersion version;
/// <summary>
/// Creates a new RopeTextSource.
/// </summary>
public RopeTextSource(Rope<char> rope)
{
if (rope == null)
throw new ArgumentNullException("rope");
this.rope = rope.Clone();
}
/// <summary>
/// Creates a new RopeTextSource.
/// </summary>
public RopeTextSource(Rope<char> rope, ITextSourceVersion version)
{
if (rope == null)
throw new ArgumentNullException("rope");
this.rope = rope.Clone();
this.version = version;
}
/// <summary>
/// Returns a clone of the rope used for this text source.
/// </summary>
/// <remarks>
/// RopeTextSource only publishes a copy of the contained rope to ensure that the underlying rope cannot be modified.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification="Not a property because it creates a clone")]
public Rope<char> GetRope()
{
return rope.Clone();
}
/// <inheritdoc/>
public string Text {
get { return rope.ToString(); }
}
/// <inheritdoc/>
public int TextLength {
get { return rope.Length; }
}
/// <inheritdoc/>
public char GetCharAt(int offset)
{
return rope[offset];
}
/// <inheritdoc/>
public string GetText(int offset, int length)
{
return rope.ToString(offset, length);
}
/// <inheritdoc/>
public string GetText(ISegment segment)
{
return rope.ToString(segment.Offset, segment.Length);
}
/// <inheritdoc/>
public TextReader CreateReader()
{
return new RopeTextReader(rope);
}
/// <inheritdoc/>
public TextReader CreateReader(int offset, int length)
{
return new RopeTextReader(rope.GetRange(offset, length));
}
/// <inheritdoc/>
public ITextSource CreateSnapshot()
{
return this;
}
/// <inheritdoc/>
public ITextSource CreateSnapshot(int offset, int length)
{
return new RopeTextSource(rope.GetRange(offset, length));
}
/// <inheritdoc/>
public int IndexOf(char c, int startIndex, int count)
{
return rope.IndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
return rope.IndexOfAny(anyOf, startIndex, count);
}
/// <inheritdoc/>
public int LastIndexOf(char c, int startIndex, int count)
{
return rope.LastIndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public ITextSourceVersion Version {
get { return version; }
}
/// <inheritdoc/>
public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{
return rope.IndexOf(searchText, startIndex, count, comparisonType);
}
/// <inheritdoc/>
public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{
return rope.LastIndexOf(searchText, startIndex, count, comparisonType);
}
/// <inheritdoc/>
public void WriteTextTo(TextWriter writer)
{
rope.WriteTo(writer, 0, rope.Length);
}
/// <inheritdoc/>
public void WriteTextTo(TextWriter writer, int offset, int length)
{
rope.WriteTo(writer, offset, length);
}
}
}

80
AvalonEdit/ICSharpCode.AvalonEdit/Document/ISegment.cs → AvalonEdit/ICSharpCode.AvalonEdit/Document/SimpleSegment.cs

@ -1,75 +1,52 @@ @@ -1,75 +1,52 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;
using ICSharpCode.AvalonEdit.Utils;
using System.Globalization;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{
/// <summary>
/// An (Offset,Length)-pair.
/// Represents a simple segment (Offset,Length pair) that is not automatically updated
/// on document changes.
/// </summary>
/// <seealso cref="TextSegment"/>
/// <seealso cref="AnchorSegment"/>
public interface ISegment
{
/// <summary>
/// Gets the start offset of the segment.
/// </summary>
int Offset { get; }
/// <summary>
/// Gets the length of the segment.
/// </summary>
/// <remarks>Must not be negative.</remarks>
int Length { get; }
/// <summary>
/// Gets the end offset of the segment.
/// </summary>
/// <remarks>EndOffset = Offset + Length;</remarks>
int EndOffset { get; }
}
static class SegmentExtensions
struct SimpleSegment : IEquatable<SimpleSegment>, ISegment
{
/// <summary>
/// Gets whether the segment contains the offset.
/// </summary>
/// <returns>
/// True, if offset is between segment.Start and segment.End (inclusive); otherwise, false.
/// </returns>
public static bool Contains(this ISegment segment, int offset)
{
int start = segment.Offset;
int end = start + segment.Length;
return offset >= start && offset <= end;
}
public static readonly SimpleSegment Invalid = new SimpleSegment(-1, -1);
/// <summary>
/// Gets the overlapping portion of the segments.
/// Returns SimpleSegment.Invalid if the segments don't overlap.
/// </summary>
public static SimpleSegment GetOverlap(this ISegment segment, ISegment other)
public static SimpleSegment GetOverlap(ISegment segment1, ISegment segment2)
{
int start = Math.Max(segment.Offset, other.Offset);
int end = Math.Min(segment.EndOffset, other.EndOffset);
int start = Math.Max(segment1.Offset, segment2.Offset);
int end = Math.Min(segment1.EndOffset, segment2.EndOffset);
if (end < start)
return SimpleSegment.Invalid;
else
return new SimpleSegment(start, end - start);
}
}
/// <summary>
/// Represents a simple segment (Offset,Length pair) that is not automatically updated
/// on document changes.
/// </summary>
struct SimpleSegment : IEquatable<SimpleSegment>, ISegment
{
public static readonly SimpleSegment Invalid = new SimpleSegment(-1, -1);
public readonly int Offset, Length;
@ -127,6 +104,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -127,6 +104,7 @@ namespace ICSharpCode.AvalonEdit.Document
return !left.Equals(right);
}
/// <inheritdoc/>
public override string ToString()
{
return "[Offset=" + Offset.ToString(CultureInfo.InvariantCulture) + ", Length=" + Length.ToString(CultureInfo.InvariantCulture) + "]";

86
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextAnchor.cs

@ -1,8 +1,26 @@ @@ -1,8 +1,26 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.AvalonEdit.Document
{
@ -33,7 +51,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -33,7 +51,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// int newOffset = anchor.Offset;
/// </code>
/// </example>
public sealed class TextAnchor
public sealed class TextAnchor : ITextAnchor
{
readonly TextDocument document;
internal TextAnchorNode node;
@ -50,37 +68,13 @@ namespace ICSharpCode.AvalonEdit.Document @@ -50,37 +68,13 @@ namespace ICSharpCode.AvalonEdit.Document
get { return document; }
}
/// <summary>
/// Controls how the anchor moves.
/// </summary>
/// <remarks>Anchor movement is ambiguous if text is inserted exactly at the anchor's location.
/// Does the anchor stay before the inserted text, or does it move after it?
/// The property <see cref="MovementType"/> will be used to determine which of these two options the anchor will choose.
/// The default value is <see cref="AnchorMovementType.Default"/>.</remarks>
/// <inheritdoc/>
public AnchorMovementType MovementType { get; set; }
/// <summary>
/// <para>
/// Specifies whether the anchor survives deletion of the text containing it.
/// </para><para>
/// <c>false</c>: The anchor is deleted when the a selection that includes the anchor is deleted.
/// <c>true</c>: The anchor is not deleted.
/// </para>
/// </summary>
/// <remarks><inheritdoc cref="IsDeleted" /></remarks>
/// <inheritdoc/>
public bool SurviveDeletion { get; set; }
/// <summary>
/// Gets whether the anchor was deleted.
/// </summary>
/// <remarks>
/// <para>When a piece of text containing an anchor is removed, then that anchor will be deleted.
/// First, the <see cref="IsDeleted"/> property is set to true on all deleted anchors,
/// then the <see cref="Deleted"/> events are raised.
/// You cannot retrieve the offset from an anchor that has been deleted.</para>
/// <para>This deletion behavior might be useful when using anchors for building a bookmark feature,
/// but in other cases you want to still be able to use the anchor. For those cases, set <c><see cref="SurviveDeletion"/> = true</c>.</para>
/// </remarks>
/// <inheritdoc/>
public bool IsDeleted {
get {
document.DebugVerifyAccess();
@ -88,14 +82,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -88,14 +82,7 @@ namespace ICSharpCode.AvalonEdit.Document
}
}
/// <summary>
/// Occurs after the anchor was deleted.
/// </summary>
/// <remarks>
/// <inheritdoc cref="IsDeleted" />
/// <para>Due to the 'weak reference' nature of TextAnchor, you will receive the Deleted event only
/// while your code holds a reference to the TextAnchor object.</para>
/// </remarks>
/// <inheritdoc/>
public event EventHandler Deleted;
internal void OnDeleted(DelayedEvents delayedEvents)
@ -168,27 +155,4 @@ namespace ICSharpCode.AvalonEdit.Document @@ -168,27 +155,4 @@ namespace ICSharpCode.AvalonEdit.Document
return "[TextAnchor Offset=" + Offset + "]";
}
}
/// <summary>
/// Defines how a text anchor moves.
/// </summary>
public enum AnchorMovementType
{
/// <summary>
/// When text is inserted at the anchor position, the type of the insertion
/// determines where the caret moves to. For normal insertions, the anchor will stay
/// behind the inserted text.
/// </summary>
Default,
/// <summary>
/// When text is inserted at the anchor position, the anchor will stay
/// before the inserted text.
/// </summary>
BeforeInsertion,
/// <summary>
/// When text is insered at the anchor position, the anchor will move
/// after the inserted text.
/// </summary>
AfterInsertion
}
}

19
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextAnchorNode.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;

23
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextAnchorTree.cs

@ -1,12 +1,29 @@ @@ -1,12 +1,29 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{

423
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs

@ -1,16 +1,32 @@ @@ -1,16 +1,32 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Linq;
using System.Globalization;
using System.Linq.Expressions;
using System.Threading;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.AvalonEdit.Document
{
@ -22,7 +38,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -22,7 +38,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// <inheritdoc cref="VerifyAccess"/>
/// <para>However, there is a single method that is thread-safe: <see cref="CreateSnapshot()"/> (and its overloads).</para>
/// </remarks>
public sealed class TextDocument : ITextSource, INotifyPropertyChanged
public sealed class TextDocument : IDocument, INotifyPropertyChanged
{
#region Thread ownership
readonly object lockObject = new object();
@ -73,7 +89,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -73,7 +89,7 @@ namespace ICSharpCode.AvalonEdit.Document
readonly DocumentLineTree lineTree;
readonly LineManager lineManager;
readonly TextAnchorTree anchorTree;
ChangeTrackingCheckpoint currentCheckpoint;
readonly TextSourceVersionProvider versionProvider = new TextSourceVersionProvider();
/// <summary>
/// Create an empty text document.
@ -116,6 +132,11 @@ namespace ICSharpCode.AvalonEdit.Document @@ -116,6 +132,11 @@ namespace ICSharpCode.AvalonEdit.Document
if (textSource == null)
throw new ArgumentNullException("textSource");
#if NREFACTORY
if (textSource is ReadOnlyDocument)
textSource = textSource.CreateSnapshot(); // retrieve underlying text source, which might be a RopeTextSource
#endif
RopeTextSource rts = textSource as RopeTextSource;
if (rts != null)
return rts.GetRope();
@ -156,12 +177,41 @@ namespace ICSharpCode.AvalonEdit.Document @@ -156,12 +177,41 @@ namespace ICSharpCode.AvalonEdit.Document
return GetText(segment.Offset, segment.Length);
}
int ITextSource.IndexOfAny(char[] anyOf, int startIndex, int count)
/// <inheritdoc/>
public int IndexOf(char c, int startIndex, int count)
{
DebugVerifyAccess();
return rope.IndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public int LastIndexOf(char c, int startIndex, int count)
{
DebugVerifyAccess();
return rope.LastIndexOf(c, startIndex, count);
}
/// <inheritdoc/>
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
DebugVerifyAccess(); // frequently called (NewLineFinder), so must be fast in release builds
return rope.IndexOfAny(anyOf, startIndex, count);
}
/// <inheritdoc/>
public int IndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{
DebugVerifyAccess();
return rope.IndexOf(searchText, startIndex, count, comparisonType);
}
/// <inheritdoc/>
public int LastIndexOf(string searchText, int startIndex, int count, StringComparison comparisonType)
{
DebugVerifyAccess();
return rope.LastIndexOf(searchText, startIndex, count, comparisonType);
}
/// <inheritdoc/>
public char GetCharAt(int offset)
{
@ -192,10 +242,17 @@ namespace ICSharpCode.AvalonEdit.Document @@ -192,10 +242,17 @@ namespace ICSharpCode.AvalonEdit.Document
}
}
/// <inheritdoc/>
/// <summary>
/// This event is called after a group of changes is completed.
/// </summary>
/// <remarks><inheritdoc cref="Changing"/></remarks>
public event EventHandler TextChanged;
event EventHandler IDocument.ChangeCompleted {
add { this.TextChanged += value; }
remove { this.TextChanged -= value; }
}
/// <inheritdoc/>
public int TextLength {
get {
@ -257,12 +314,27 @@ namespace ICSharpCode.AvalonEdit.Document @@ -257,12 +314,27 @@ namespace ICSharpCode.AvalonEdit.Document
/// </remarks>
public event EventHandler<DocumentChangeEventArgs> Changing;
// Unfortunately EventHandler<T> is invariant, so we have to use two separate events
private event EventHandler<TextChangeEventArgs> textChanging;
event EventHandler<TextChangeEventArgs> IDocument.TextChanging {
add { textChanging += value; }
remove { textChanging -= value; }
}
/// <summary>
/// Is raised after the document has changed.
/// </summary>
/// <remarks><inheritdoc cref="Changing"/></remarks>
public event EventHandler<DocumentChangeEventArgs> Changed;
private event EventHandler<TextChangeEventArgs> textChanged;
event EventHandler<TextChangeEventArgs> IDocument.TextChanged {
add { textChanged += value; }
remove { textChanged -= value; }
}
/// <summary>
/// Creates a snapshot of the current text.
/// </summary>
@ -278,53 +350,63 @@ namespace ICSharpCode.AvalonEdit.Document @@ -278,53 +350,63 @@ namespace ICSharpCode.AvalonEdit.Document
public ITextSource CreateSnapshot()
{
lock (lockObject) {
return new RopeTextSource(rope.Clone());
return new RopeTextSource(rope, versionProvider.CurrentVersion);
}
}
/// <summary>
/// Creates a snapshot of the current text.
/// Additionally, creates a checkpoint that allows tracking document changes.
/// Creates a snapshot of a part of the current text.
/// </summary>
/// <remarks><inheritdoc cref="CreateSnapshot()"/><inheritdoc cref="ChangeTrackingCheckpoint"/></remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", Justification = "Need to return snapshot and checkpoint together to ensure thread-safety")]
public ITextSource CreateSnapshot(out ChangeTrackingCheckpoint checkpoint)
/// <remarks><inheritdoc cref="CreateSnapshot()"/></remarks>
public ITextSource CreateSnapshot(int offset, int length)
{
lock (lockObject) {
if (currentCheckpoint == null)
currentCheckpoint = new ChangeTrackingCheckpoint(lockObject);
checkpoint = currentCheckpoint;
return new RopeTextSource(rope.Clone());
return new RopeTextSource(rope.GetRange(offset, length));
}
}
internal ChangeTrackingCheckpoint CreateChangeTrackingCheckpoint()
#if NREFACTORY
/// <inheritdoc/>
public IDocument CreateDocumentSnapshot()
{
lock (lockObject) {
if (currentCheckpoint == null)
currentCheckpoint = new ChangeTrackingCheckpoint(lockObject);
return currentCheckpoint;
}
return new ReadOnlyDocument(this, fileName);
}
#endif
/// <summary>
/// Creates a snapshot of a part of the current text.
/// </summary>
/// <remarks><inheritdoc cref="CreateSnapshot()"/></remarks>
public ITextSource CreateSnapshot(int offset, int length)
/// <inheritdoc/>
public ITextSourceVersion Version {
get { return versionProvider.CurrentVersion; }
}
/// <inheritdoc/>
public System.IO.TextReader CreateReader()
{
lock (lockObject) {
return new RopeTextSource(rope.GetRange(offset, length));
return new RopeTextReader(rope);
}
}
/// <inheritdoc/>
public System.IO.TextReader CreateReader()
public System.IO.TextReader CreateReader(int offset, int length)
{
lock (lockObject) {
return new RopeTextReader(rope);
return new RopeTextReader(rope.GetRange(offset, length));
}
}
/// <inheritdoc/>
public void WriteTextTo(System.IO.TextWriter writer)
{
VerifyAccess();
rope.WriteTo(writer, 0, rope.Length);
}
/// <inheritdoc/>
public void WriteTextTo(System.IO.TextWriter writer, int offset, int length)
{
VerifyAccess();
rope.WriteTo(writer, offset, length);
}
#endregion
#region BeginUpdate / EndUpdate
@ -408,6 +490,21 @@ namespace ICSharpCode.AvalonEdit.Document @@ -408,6 +490,21 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
/// <remarks><inheritdoc cref="Changing"/></remarks>
public event EventHandler UpdateFinished;
void IDocument.StartUndoableAction()
{
BeginUpdate();
}
void IDocument.EndUndoableAction()
{
EndUpdate();
}
IDisposable IDocument.OpenUndoGroup()
{
return RunUpdate();
}
#endregion
#region Fire events after update
@ -456,9 +553,69 @@ namespace ICSharpCode.AvalonEdit.Document @@ -456,9 +553,69 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <remarks>
/// Anchors positioned exactly at the insertion offset will move according to their movement type.
/// For AnchorMovementType.Default, they will move behind the inserted text.
/// The caret will also move behind the inserted text.
/// </remarks>
public void Insert(int offset, string text)
{
Replace(offset, 0, text);
Replace(offset, 0, new StringTextSource(text), null);
}
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <remarks>
/// Anchors positioned exactly at the insertion offset will move according to their movement type.
/// For AnchorMovementType.Default, they will move behind the inserted text.
/// The caret will also move behind the inserted text.
/// </remarks>
public void Insert(int offset, ITextSource text)
{
Replace(offset, 0, text, null);
}
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <param name="defaultAnchorMovementType">
/// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type.
/// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter.
/// The caret will also move according to the <paramref name="defaultAnchorMovementType"/> parameter.
/// </param>
public void Insert(int offset, string text, AnchorMovementType defaultAnchorMovementType)
{
if (defaultAnchorMovementType == AnchorMovementType.BeforeInsertion) {
Replace(offset, 0, new StringTextSource(text), OffsetChangeMappingType.KeepAnchorBeforeInsertion);
} else {
Replace(offset, 0, new StringTextSource(text), null);
}
}
/// <summary>
/// Inserts text.
/// </summary>
/// <param name="offset">The offset at which the text is inserted.</param>
/// <param name="text">The new text.</param>
/// <param name="defaultAnchorMovementType">
/// Anchors positioned exactly at the insertion offset will move according to the anchor's movement type.
/// For AnchorMovementType.Default, they will move according to the movement type specified by this parameter.
/// The caret will also move according to the <paramref name="defaultAnchorMovementType"/> parameter.
/// </param>
public void Insert(int offset, ITextSource text, AnchorMovementType defaultAnchorMovementType)
{
if (defaultAnchorMovementType == AnchorMovementType.BeforeInsertion) {
Replace(offset, 0, text, OffsetChangeMappingType.KeepAnchorBeforeInsertion);
} else {
Replace(offset, 0, text, null);
}
}
/// <summary>
@ -472,9 +629,11 @@ namespace ICSharpCode.AvalonEdit.Document @@ -472,9 +629,11 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Removes text.
/// </summary>
/// <param name="offset">Starting offset of the text to be removed.</param>
/// <param name="length">Length of the text to be removed.</param>
public void Remove(int offset, int length)
{
Replace(offset, length, string.Empty);
Replace(offset, length, StringTextSource.Empty);
}
internal bool inDocumentChanging;
@ -483,6 +642,16 @@ namespace ICSharpCode.AvalonEdit.Document @@ -483,6 +642,16 @@ namespace ICSharpCode.AvalonEdit.Document
/// Replaces text.
/// </summary>
public void Replace(ISegment segment, string text)
{
if (segment == null)
throw new ArgumentNullException("segment");
Replace(segment.Offset, segment.Length, new StringTextSource(text), null);
}
/// <summary>
/// Replaces text.
/// </summary>
public void Replace(ISegment segment, ITextSource text)
{
if (segment == null)
throw new ArgumentNullException("segment");
@ -492,7 +661,21 @@ namespace ICSharpCode.AvalonEdit.Document @@ -492,7 +661,21 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Replaces text.
/// </summary>
/// <param name="offset">The starting offset of the text to be replaced.</param>
/// <param name="length">The length of the text to be replaced.</param>
/// <param name="text">The new text.</param>
public void Replace(int offset, int length, string text)
{
Replace(offset, length, new StringTextSource(text), null);
}
/// <summary>
/// Replaces text.
/// </summary>
/// <param name="offset">The starting offset of the text to be replaced.</param>
/// <param name="length">The length of the text to be replaced.</param>
/// <param name="text">The new text.</param>
public void Replace(int offset, int length, ITextSource text)
{
Replace(offset, length, text, null);
}
@ -506,6 +689,19 @@ namespace ICSharpCode.AvalonEdit.Document @@ -506,6 +689,19 @@ namespace ICSharpCode.AvalonEdit.Document
/// <param name="offsetChangeMappingType">The offsetChangeMappingType determines how offsets inside the old text are mapped to the new text.
/// This affects how the anchors and segments inside the replaced region behave.</param>
public void Replace(int offset, int length, string text, OffsetChangeMappingType offsetChangeMappingType)
{
Replace(offset, length, new StringTextSource(text), offsetChangeMappingType);
}
/// <summary>
/// Replaces text.
/// </summary>
/// <param name="offset">The starting offset of the text to be replaced.</param>
/// <param name="length">The length of the text to be replaced.</param>
/// <param name="text">The new text.</param>
/// <param name="offsetChangeMappingType">The offsetChangeMappingType determines how offsets inside the old text are mapped to the new text.
/// This affects how the anchors and segments inside the replaced region behave.</param>
public void Replace(int offset, int length, ITextSource text, OffsetChangeMappingType offsetChangeMappingType)
{
if (text == null)
throw new ArgumentNullException("text");
@ -516,33 +712,33 @@ namespace ICSharpCode.AvalonEdit.Document @@ -516,33 +712,33 @@ namespace ICSharpCode.AvalonEdit.Document
break;
case OffsetChangeMappingType.KeepAnchorBeforeInsertion:
Replace(offset, length, text, OffsetChangeMap.FromSingleElement(
new OffsetChangeMapEntry(offset, length, text.Length, false, true)));
new OffsetChangeMapEntry(offset, length, text.TextLength, false, true)));
break;
case OffsetChangeMappingType.RemoveAndInsert:
if (length == 0 || text.Length == 0) {
if (length == 0 || text.TextLength == 0) {
// only insertion or only removal?
// OffsetChangeMappingType doesn't matter, just use Normal.
Replace(offset, length, text, null);
} else {
OffsetChangeMap map = new OffsetChangeMap(2);
map.Add(new OffsetChangeMapEntry(offset, length, 0));
map.Add(new OffsetChangeMapEntry(offset, 0, text.Length));
map.Add(new OffsetChangeMapEntry(offset, 0, text.TextLength));
map.Freeze();
Replace(offset, length, text, map);
}
break;
case OffsetChangeMappingType.CharacterReplace:
if (length == 0 || text.Length == 0) {
if (length == 0 || text.TextLength == 0) {
// only insertion or only removal?
// OffsetChangeMappingType doesn't matter, just use Normal.
Replace(offset, length, text, null);
} else if (text.Length > length) {
} else if (text.TextLength > length) {
// look at OffsetChangeMappingType.CharacterReplace XML comments on why we need to replace
// the last character
OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + length - 1, 1, 1 + text.Length - length);
OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + length - 1, 1, 1 + text.TextLength - length);
Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry));
} else if (text.Length < length) {
OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + text.Length, length - text.Length, 0, true, false);
} else if (text.TextLength < length) {
OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + text.TextLength, length - text.TextLength, 0, true, false);
Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry));
} else {
Replace(offset, length, text, OffsetChangeMap.Empty);
@ -569,10 +765,30 @@ namespace ICSharpCode.AvalonEdit.Document @@ -569,10 +765,30 @@ namespace ICSharpCode.AvalonEdit.Document
/// DocumentChangeEventArgs instance.
/// </param>
public void Replace(int offset, int length, string text, OffsetChangeMap offsetChangeMap)
{
Replace(offset, length, new StringTextSource(text), offsetChangeMap);
}
/// <summary>
/// Replaces text.
/// </summary>
/// <param name="offset">The starting offset of the text to be replaced.</param>
/// <param name="length">The length of the text to be replaced.</param>
/// <param name="text">The new text.</param>
/// <param name="offsetChangeMap">The offsetChangeMap determines how offsets inside the old text are mapped to the new text.
/// This affects how the anchors and segments inside the replaced region behave.
/// If you pass null (the default when using one of the other overloads), the offsets are changed as
/// in OffsetChangeMappingType.Normal mode.
/// If you pass OffsetChangeMap.Empty, then everything will stay in its old place (OffsetChangeMappingType.CharacterReplace mode).
/// The offsetChangeMap must be a valid 'explanation' for the document change. See <see cref="OffsetChangeMap.IsValidForDocumentChange"/>.
/// Passing an OffsetChangeMap to the Replace method will automatically freeze it to ensure the thread safety of the resulting
/// DocumentChangeEventArgs instance.
/// </param>
public void Replace(int offset, int length, ITextSource text, OffsetChangeMap offsetChangeMap)
{
if (text == null)
throw new ArgumentNullException("text");
text = text.CreateSnapshot();
if (offsetChangeMap != null)
offsetChangeMap.Freeze();
@ -596,23 +812,33 @@ namespace ICSharpCode.AvalonEdit.Document @@ -596,23 +812,33 @@ namespace ICSharpCode.AvalonEdit.Document
}
}
void DoReplace(int offset, int length, string newText, OffsetChangeMap offsetChangeMap)
void DoReplace(int offset, int length, ITextSource newText, OffsetChangeMap offsetChangeMap)
{
if (length == 0 && newText.Length == 0)
if (length == 0 && newText.TextLength == 0)
return;
// trying to replace a single character in 'Normal' mode?
// for single characters, 'CharacterReplace' mode is equivalent, but more performant
// (we don't have to touch the anchorTree at all in 'CharacterReplace' mode)
if (length == 1 && newText.Length == 1 && offsetChangeMap == null)
if (length == 1 && newText.TextLength == 1 && offsetChangeMap == null)
offsetChangeMap = OffsetChangeMap.Empty;
string removedText = rope.ToString(offset, length);
ITextSource removedText;
if (length == 0) {
removedText = StringTextSource.Empty;
} else if (length < 100) {
removedText = new StringTextSource(rope.ToString(offset, length));
} else {
// use a rope if the removed string is long
removedText = new RopeTextSource(rope.GetRange(offset, length));
}
DocumentChangeEventArgs args = new DocumentChangeEventArgs(offset, removedText, newText, offsetChangeMap);
// fire DocumentChanging event
if (Changing != null)
Changing(this, args);
if (textChanging != null)
textChanging(this, args);
undoStack.Push(this, args);
@ -621,16 +847,18 @@ namespace ICSharpCode.AvalonEdit.Document @@ -621,16 +847,18 @@ namespace ICSharpCode.AvalonEdit.Document
DelayedEvents delayedEvents = new DelayedEvents();
lock (lockObject) {
// create linked list of checkpoints, if required
if (currentCheckpoint != null) {
currentCheckpoint = currentCheckpoint.Append(args);
}
// create linked list of checkpoints
versionProvider.AppendChange(args);
// now update the textBuffer and lineTree
if (offset == 0 && length == rope.Length) {
// optimize replacing the whole document
rope.Clear();
rope.InsertText(0, newText);
var newRopeTextSource = newText as RopeTextSource;
if (newRopeTextSource != null)
rope.InsertRange(0, newRopeTextSource.GetRope());
else
rope.InsertText(0, newText.Text);
lineManager.Rebuild();
} else {
rope.RemoveRange(offset, length);
@ -638,7 +866,11 @@ namespace ICSharpCode.AvalonEdit.Document @@ -638,7 +866,11 @@ namespace ICSharpCode.AvalonEdit.Document
#if DEBUG
lineTree.CheckProperties();
#endif
rope.InsertText(offset, newText);
var newRopeTextSource = newText as RopeTextSource;
if (newRopeTextSource != null)
rope.InsertRange(offset, newRopeTextSource.GetRope());
else
rope.InsertText(offset, newText.Text);
lineManager.Insert(offset, newText);
#if DEBUG
lineTree.CheckProperties();
@ -655,12 +887,16 @@ namespace ICSharpCode.AvalonEdit.Document @@ -655,12 +887,16 @@ namespace ICSharpCode.AvalonEdit.Document
}
}
lineManager.ChangeComplete(args);
// raise delayed events after our data structures are consistent again
delayedEvents.RaiseEvents();
// fire DocumentChanged event
if (Changed != null)
Changed(this, args);
if (textChanged != null)
textChanged(this, args);
}
#endregion
@ -684,6 +920,11 @@ namespace ICSharpCode.AvalonEdit.Document @@ -684,6 +920,11 @@ namespace ICSharpCode.AvalonEdit.Document
return lineTree.GetByNumber(number);
}
IDocumentLine IDocument.GetLineByNumber(int lineNumber)
{
return GetLineByNumber(lineNumber);
}
/// <summary>
/// Gets a document lines by offset.
/// Runtime: O(log n)
@ -697,8 +938,14 @@ namespace ICSharpCode.AvalonEdit.Document @@ -697,8 +938,14 @@ namespace ICSharpCode.AvalonEdit.Document
}
return lineTree.GetByOffset(offset);
}
IDocumentLine IDocument.GetLineByOffset(int offset)
{
return GetLineByOffset(offset);
}
#endregion
#region GetOffset / GetLocation
/// <summary>
/// Gets the offset from a text location.
/// </summary>
@ -731,7 +978,9 @@ namespace ICSharpCode.AvalonEdit.Document @@ -731,7 +978,9 @@ namespace ICSharpCode.AvalonEdit.Document
DocumentLine line = GetLineByOffset(offset);
return new TextLocation(line.LineNumber, offset - line.Offset + 1);
}
#endregion
#region Line Trackers
readonly ObservableCollection<ILineTracker> lineTrackers = new ObservableCollection<ILineTracker>();
/// <summary>
@ -744,7 +993,9 @@ namespace ICSharpCode.AvalonEdit.Document @@ -744,7 +993,9 @@ namespace ICSharpCode.AvalonEdit.Document
return lineTrackers;
}
}
#endregion
#region UndoStack
UndoStack undoStack;
/// <summary>
@ -764,7 +1015,9 @@ namespace ICSharpCode.AvalonEdit.Document @@ -764,7 +1015,9 @@ namespace ICSharpCode.AvalonEdit.Document
}
}
}
#endregion
#region CreateAnchor
/// <summary>
/// Creates a new <see cref="TextAnchor"/> at the specified offset.
/// </summary>
@ -778,6 +1031,12 @@ namespace ICSharpCode.AvalonEdit.Document @@ -778,6 +1031,12 @@ namespace ICSharpCode.AvalonEdit.Document
return anchorTree.CreateAnchor(offset);
}
ITextAnchor IDocument.CreateAnchor(int offset)
{
return CreateAnchor(offset);
}
#endregion
#region LineCount
/// <summary>
/// Gets the total number of lines in the document.
@ -832,5 +1091,63 @@ namespace ICSharpCode.AvalonEdit.Document @@ -832,5 +1091,63 @@ namespace ICSharpCode.AvalonEdit.Document
#endif
}
#endregion
#region Service Provider
IServiceProvider serviceProvider;
/// <summary>
/// Gets/Sets the service provider associated with this document.
/// By default, every TextDocument has its own ServiceContainer; and has the document itself
/// registered as <see cref="IDocument"/> and <see cref="TextDocument"/>.
/// </summary>
public IServiceProvider ServiceProvider {
get {
VerifyAccess();
if (serviceProvider == null) {
var container = new ServiceContainer();
container.AddService(typeof(IDocument), this);
container.AddService(typeof(TextDocument), this);
serviceProvider = container;
}
return serviceProvider;
}
set {
VerifyAccess();
if (value == null)
throw new ArgumentNullException();
serviceProvider = value;
}
}
object IServiceProvider.GetService(Type serviceType)
{
return this.ServiceProvider.GetService(serviceType);
}
#endregion
#region FileName
string fileName;
/// <inheritdoc/>
public event EventHandler FileNameChanged;
void OnFileNameChanged(EventArgs e)
{
EventHandler handler = this.FileNameChanged;
if (handler != null)
handler(this, e);
}
/// <inheritdoc/>
public string FileName {
get { return fileName; }
set {
if (fileName != value) {
fileName = value;
OnFileNameChanged(EventArgs.Empty);
}
}
}
#endregion
}
}

22
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocumentWeakEventManager.cs

@ -1,7 +1,25 @@ @@ -1,7 +1,25 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Document

153
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextLocation.cs

@ -1,19 +1,38 @@ @@ -1,19 +1,38 @@
// 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)
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.ComponentModel;
using System.Globalization;
namespace ICSharpCode.AvalonEdit.Document
{
#if !NREFACTORY
/// <summary>
/// A line/column position.
/// Text editor lines/columns are counted started from one.
/// </summary>
/// <remarks>
/// The document provides the methods <see cref="TextDocument.GetLocation"/> and
/// <see cref="TextDocument.GetOffset(TextLocation)"/> to convert between offsets and TextLocations.
/// The document provides the methods <see cref="IDocument.GetLocation"/> and
/// <see cref="IDocument.GetOffset(TextLocation)"/> to convert between offsets and TextLocations.
/// </remarks>
[Serializable]
[TypeConverter(typeof(TextLocationConverter))]
public struct TextLocation : IComparable<TextLocation>, IEquatable<TextLocation>
{
/// <summary>
@ -23,31 +42,27 @@ namespace ICSharpCode.AvalonEdit.Document @@ -23,31 +42,27 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Creates a TextLocation instance.
/// <para>
/// Warning: the parameters are (line, column).
/// Not (column, line) as in ICSharpCode.TextEditor!
/// </para>
/// </summary>
public TextLocation(int line, int column)
{
y = line;
x = column;
this.line = line;
this.column = column;
}
int x, y;
readonly int column, line;
/// <summary>
/// Gets the line number.
/// </summary>
public int Line {
get { return y; }
get { return line; }
}
/// <summary>
/// Gets the column number.
/// </summary>
public int Column {
get { return x; }
get { return column; }
}
/// <summary>
@ -55,7 +70,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -55,7 +70,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
public bool IsEmpty {
get {
return x <= 0 && y <= 0;
return column <= 0 && line <= 0;
}
}
@ -64,7 +79,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -64,7 +79,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "(Line {1}, Col {0})", this.x, this.y);
return string.Format(CultureInfo.InvariantCulture, "(Line {1}, Col {0})", this.column, this.line);
}
/// <summary>
@ -72,7 +87,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -72,7 +87,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
public override int GetHashCode()
{
return unchecked (87 * x.GetHashCode() ^ y.GetHashCode());
return unchecked (191 * column.GetHashCode() ^ line.GetHashCode());
}
/// <summary>
@ -97,7 +112,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -97,7 +112,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
public static bool operator ==(TextLocation left, TextLocation right)
{
return left.x == right.x && left.y == right.y;
return left.column == right.column && left.line == right.line;
}
/// <summary>
@ -105,7 +120,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -105,7 +120,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
public static bool operator !=(TextLocation left, TextLocation right)
{
return left.x != right.x || left.y != right.y;
return left.column != right.column || left.line != right.line;
}
/// <summary>
@ -113,10 +128,10 @@ namespace ICSharpCode.AvalonEdit.Document @@ -113,10 +128,10 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
public static bool operator <(TextLocation left, TextLocation right)
{
if (left.y < right.y)
if (left.line < right.line)
return true;
else if (left.y == right.y)
return left.x < right.x;
else if (left.line == right.line)
return left.column < right.column;
else
return false;
}
@ -126,10 +141,10 @@ namespace ICSharpCode.AvalonEdit.Document @@ -126,10 +141,10 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
public static bool operator >(TextLocation left, TextLocation right)
{
if (left.y > right.y)
if (left.line > right.line)
return true;
else if (left.y == right.y)
return left.x > right.x;
else if (left.line == right.line)
return left.column > right.column;
else
return false;
}
@ -163,4 +178,94 @@ namespace ICSharpCode.AvalonEdit.Document @@ -163,4 +178,94 @@ namespace ICSharpCode.AvalonEdit.Document
return 1;
}
}
/// <summary>
/// Converts strings of the form '0+[;,]0+' to a <see cref="TextLocation"/>.
/// </summary>
public class TextLocationConverter : TypeConverter
{
/// <inheritdoc/>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc/>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(TextLocation) || base.CanConvertTo(context, destinationType);
}
/// <inheritdoc/>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string) {
string[] parts = ((string)value).Split(';', ',');
if (parts.Length == 2) {
return new TextLocation(int.Parse(parts[0], culture), int.Parse(parts[1], culture));
}
}
return base.ConvertFrom(context, culture, value);
}
/// <inheritdoc/>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value is TextLocation && destinationType == typeof(string)) {
var loc = (TextLocation)value;
return loc.Line.ToString(culture) + ";" + loc.Column.ToString(culture);
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
/// <summary>
/// An (Offset,Length)-pair.
/// </summary>
public interface ISegment
{
/// <summary>
/// Gets the start offset of the segment.
/// </summary>
int Offset { get; }
/// <summary>
/// Gets the length of the segment.
/// </summary>
/// <remarks>For line segments (IDocumentLine), the length does not include the line delimeter.</remarks>
int Length { get; }
/// <summary>
/// Gets the end offset of the segment.
/// </summary>
/// <remarks>EndOffset = Offset + Length;</remarks>
int EndOffset { get; }
}
/// <summary>
/// Extension methods for <see cref="ISegment"/>.
/// </summary>
public static class ISegmentExtensions
{
/// <summary>
/// Gets whether <paramref name="segment"/> fully contains the specified segment.
/// </summary>
/// <remarks>
/// Use <c>segment.Contains(offset, 0)</c> to detect whether a segment (end inclusive) contains offset;
/// use <c>segment.Contains(offset, 1)</c> to detect whether a segment (end exclusive) contains offset.
/// </remarks>
public static bool Contains (this ISegment segment, int offset, int length)
{
return segment.Offset <= offset && offset + length <= segment.EndOffset;
}
/// <summary>
/// Gets whether <paramref name="thisSegment"/> fully contains the specified segment.
/// </summary>
public static bool Contains (this ISegment thisSegment, ISegment segment)
{
return segment != null && thisSegment.Offset <= segment.Offset && segment.EndOffset <= thisSegment.EndOffset;
}
}
#endif
}

40
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegment.cs

@ -1,8 +1,26 @@ @@ -1,8 +1,26 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{
@ -120,6 +138,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -120,6 +138,7 @@ namespace ICSharpCode.AvalonEdit.Document
} else {
nodeLength = value;
}
OnSegmentChanged();
}
}
}
@ -155,12 +174,23 @@ namespace ICSharpCode.AvalonEdit.Document @@ -155,12 +174,23 @@ namespace ICSharpCode.AvalonEdit.Document
set {
if (value < 0)
throw new ArgumentOutOfRangeException("value", "Length must not be negative");
segmentLength = value;
if (ownerTree != null)
ownerTree.UpdateAugmentedData(this);
if (segmentLength != value) {
segmentLength = value;
if (ownerTree != null)
ownerTree.UpdateAugmentedData(this);
OnSegmentChanged();
}
}
}
/// <summary>
/// This method gets called when the StartOffset/Length/EndOffset properties are set.
/// It is not called when StartOffset/Length/EndOffset change due to document changes
/// </summary>
protected virtual void OnSegmentChanged()
{
}
internal TextSegment LeftMost {
get {
TextSegment node = this;

24
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSegmentCollection.cs

@ -1,7 +1,21 @@ @@ -1,7 +1,21 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.AvalonEdit.Utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@ -9,6 +23,10 @@ using System.Diagnostics; @@ -9,6 +23,10 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{

136
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextSourceVersionProvider.cs

@ -0,0 +1,136 @@ @@ -0,0 +1,136 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Document
{
#if !NREFACTORY
/// <summary>
/// Provides ITextSourceVersion instances.
/// </summary>
public class TextSourceVersionProvider
{
Version currentVersion;
/// <summary>
/// Creates a new TextSourceVersionProvider instance.
/// </summary>
public TextSourceVersionProvider()
{
this.currentVersion = new Version(this);
}
/// <summary>
/// Gets the current version.
/// </summary>
public ITextSourceVersion CurrentVersion {
get { return currentVersion; }
}
/// <summary>
/// Replaces the current version with a new version.
/// </summary>
/// <param name="change">Change from current version to new version</param>
public void AppendChange(TextChangeEventArgs change)
{
if (change == null)
throw new ArgumentNullException("change");
currentVersion.change = change;
currentVersion.next = new Version(currentVersion);
currentVersion = currentVersion.next;
}
[DebuggerDisplay("Version #{id}")]
sealed class Version : ITextSourceVersion
{
// Reference back to the provider.
// Used to determine if two checkpoints belong to the same document.
readonly TextSourceVersionProvider provider;
// ID used for CompareAge()
readonly int id;
// the change from this version to the next version
internal TextChangeEventArgs change;
internal Version next;
internal Version(TextSourceVersionProvider provider)
{
this.provider = provider;
}
internal Version(Version prev)
{
this.provider = prev.provider;
this.id = unchecked( prev.id + 1 );
}
public bool BelongsToSameDocumentAs(ITextSourceVersion other)
{
Version o = other as Version;
return o != null && provider == o.provider;
}
public int CompareAge(ITextSourceVersion other)
{
if (other == null)
throw new ArgumentNullException("other");
Version o = other as Version;
if (o == null || provider != o.provider)
throw new ArgumentException("Versions do not belong to the same document.");
// We will allow overflows, but assume that the maximum distance between checkpoints is 2^31-1.
// This is guaranteed on x86 because so many checkpoints don't fit into memory.
return Math.Sign(unchecked( this.id - o.id ));
}
public IEnumerable<TextChangeEventArgs> GetChangesTo(ITextSourceVersion other)
{
int result = CompareAge(other);
Version o = (Version)other;
if (result < 0)
return GetForwardChanges(o);
else if (result > 0)
return o.GetForwardChanges(this).Reverse().Select(change => change.Invert());
else
return Empty<TextChangeEventArgs>.Array;
}
IEnumerable<TextChangeEventArgs> GetForwardChanges(Version other)
{
// Return changes from this(inclusive) to other(exclusive).
for (Version node = this; node != other; node = node.next) {
yield return node.change;
}
}
public int MoveOffsetTo(ITextSourceVersion other, int oldOffset, AnchorMovementType movement)
{
int offset = oldOffset;
foreach (var e in GetChangesTo(other)) {
offset = e.GetNewOffset(offset, movement);
}
return offset;
}
}
}
#endif
}

170
AvalonEdit/ICSharpCode.AvalonEdit/Document/TextUtilities.cs

@ -1,9 +1,27 @@ @@ -1,9 +1,27 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Globalization;
using System.Windows.Documents;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Document
{
@ -13,7 +31,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -13,7 +31,7 @@ namespace ICSharpCode.AvalonEdit.Document
public enum CaretPositioningMode
{
/// <summary>
/// Normal positioning (stop at every caret position)
/// Normal positioning (stop after every grapheme)
/// </summary>
Normal,
/// <summary>
@ -31,7 +49,12 @@ namespace ICSharpCode.AvalonEdit.Document @@ -31,7 +49,12 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// Stop only on word borders, and anywhere in the middle of symbols.
/// </summary>
WordBorderOrSymbol
WordBorderOrSymbol,
/// <summary>
/// Stop between every Unicode codepoint, even within the same grapheme.
/// This is used to implement deleting the previous grapheme when Backspace is pressed.
/// </summary>
EveryCodepoint
}
/// <summary>
@ -198,12 +221,43 @@ namespace ICSharpCode.AvalonEdit.Document @@ -198,12 +221,43 @@ namespace ICSharpCode.AvalonEdit.Document
{
if (c == '\r' || c == '\n')
return CharacterClass.LineTerminator;
else if (char.IsWhiteSpace(c))
return CharacterClass.Whitespace;
else if (char.IsLetterOrDigit(c) || c == '_')
if (c == '_')
return CharacterClass.IdentifierPart;
else
return GetCharacterClass(char.GetUnicodeCategory(c));
}
static CharacterClass GetCharacterClass(char highSurrogate, char lowSurrogate)
{
if (char.IsSurrogatePair(highSurrogate, lowSurrogate)) {
return GetCharacterClass(char.GetUnicodeCategory(highSurrogate.ToString() + lowSurrogate.ToString(), 0));
} else {
// malformed surrogate pair
return CharacterClass.Other;
}
}
static CharacterClass GetCharacterClass(UnicodeCategory c)
{
switch (c) {
case UnicodeCategory.SpaceSeparator:
case UnicodeCategory.LineSeparator:
case UnicodeCategory.ParagraphSeparator:
case UnicodeCategory.Control:
return CharacterClass.Whitespace;
case UnicodeCategory.UppercaseLetter:
case UnicodeCategory.LowercaseLetter:
case UnicodeCategory.TitlecaseLetter:
case UnicodeCategory.ModifierLetter:
case UnicodeCategory.OtherLetter:
case UnicodeCategory.DecimalDigitNumber:
return CharacterClass.IdentifierPart;
case UnicodeCategory.NonSpacingMark:
case UnicodeCategory.SpacingCombiningMark:
case UnicodeCategory.EnclosingMark:
return CharacterClass.CombiningMark;
default:
return CharacterClass.Other;
}
}
#endregion
@ -226,13 +280,16 @@ namespace ICSharpCode.AvalonEdit.Document @@ -226,13 +280,16 @@ namespace ICSharpCode.AvalonEdit.Document
{
if (textSource == null)
throw new ArgumentNullException("textSource");
if (mode != CaretPositioningMode.Normal
&& mode != CaretPositioningMode.WordBorder
&& mode != CaretPositioningMode.WordStart
&& mode != CaretPositioningMode.WordBorderOrSymbol
&& mode != CaretPositioningMode.WordStartOrSymbol)
{
throw new ArgumentException("Unsupported CaretPositioningMode: " + mode, "mode");
switch (mode) {
case CaretPositioningMode.Normal:
case CaretPositioningMode.EveryCodepoint:
case CaretPositioningMode.WordBorder:
case CaretPositioningMode.WordBorderOrSymbol:
case CaretPositioningMode.WordStart:
case CaretPositioningMode.WordStartOrSymbol:
break; // OK
default:
throw new ArgumentException("Unsupported CaretPositioningMode: " + mode, "mode");
}
if (direction != LogicalDirection.Backward
&& direction != LogicalDirection.Forward)
@ -242,7 +299,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -242,7 +299,7 @@ namespace ICSharpCode.AvalonEdit.Document
int textLength = textSource.TextLength;
if (textLength <= 0) {
// empty document? has a normal caret position at 0, though no word borders
if (mode == CaretPositioningMode.Normal) {
if (IsNormal(mode)) {
if (offset > 0 && direction == LogicalDirection.Backward) return 0;
if (offset < 0 && direction == LogicalDirection.Forward) return 0;
}
@ -256,44 +313,36 @@ namespace ICSharpCode.AvalonEdit.Document @@ -256,44 +313,36 @@ namespace ICSharpCode.AvalonEdit.Document
if (nextPos < 0 || nextPos > textLength)
return -1;
// stop at every caret position? we can stop immediately.
if (mode == CaretPositioningMode.Normal)
return nextPos;
// not normal mode? we're looking for word borders...
// check if we've run against the textSource borders.
// a 'textSource' usually isn't the whole document, but a single VisualLineElement.
if (nextPos == 0) {
// at the document start, there's only a word border
// if the first character is not whitespace
if (!char.IsWhiteSpace(textSource.GetCharAt(0)))
if (IsNormal(mode) || !char.IsWhiteSpace(textSource.GetCharAt(0)))
return nextPos;
} else if (nextPos == textLength) {
// at the document end, there's never a word start
if (mode != CaretPositioningMode.WordStart && mode != CaretPositioningMode.WordStartOrSymbol) {
// at the document end, there's only a word border
// if the last character is not whitespace
if (!char.IsWhiteSpace(textSource.GetCharAt(textLength - 1)))
if (IsNormal(mode) || !char.IsWhiteSpace(textSource.GetCharAt(textLength - 1)))
return nextPos;
}
} else {
CharacterClass charBefore = GetCharacterClass(textSource.GetCharAt(nextPos - 1));
CharacterClass charAfter = GetCharacterClass(textSource.GetCharAt(nextPos));
if (charBefore == charAfter) {
if (charBefore == CharacterClass.Other &&
(mode == CaretPositioningMode.WordBorderOrSymbol || mode == CaretPositioningMode.WordStartOrSymbol))
{
// With the "OrSymbol" modes, there's a word border and start between any two unknown characters
return nextPos;
char charBefore = textSource.GetCharAt(nextPos - 1);
char charAfter = textSource.GetCharAt(nextPos);
// Don't stop in the middle of a surrogate pair
if (!char.IsSurrogatePair(charBefore, charAfter)) {
CharacterClass classBefore = GetCharacterClass(charBefore);
CharacterClass classAfter = GetCharacterClass(charAfter);
// get correct class for characters outside BMP:
if (char.IsLowSurrogate(charBefore) && nextPos >= 2) {
classBefore = GetCharacterClass(textSource.GetCharAt(nextPos - 2), charBefore);
}
} else {
// this looks like a possible border
// if we're looking for word starts, check that this is a word start (and not a word end)
// if we're just checking for word borders, accept unconditionally
if (!((mode == CaretPositioningMode.WordStart || mode == CaretPositioningMode.WordStartOrSymbol)
&& (charAfter == CharacterClass.Whitespace || charAfter == CharacterClass.LineTerminator)))
{
if (char.IsHighSurrogate(charAfter) && nextPos + 1 < textLength) {
classAfter = GetCharacterClass(charAfter, textSource.GetCharAt(nextPos + 1));
}
if (StopBetweenCharacters(mode, classBefore, classAfter)) {
return nextPos;
}
}
@ -302,6 +351,42 @@ namespace ICSharpCode.AvalonEdit.Document @@ -302,6 +351,42 @@ namespace ICSharpCode.AvalonEdit.Document
offset = nextPos;
}
}
static bool IsNormal(CaretPositioningMode mode)
{
return mode == CaretPositioningMode.Normal || mode == CaretPositioningMode.EveryCodepoint;
}
static bool StopBetweenCharacters(CaretPositioningMode mode, CharacterClass charBefore, CharacterClass charAfter)
{
if (mode == CaretPositioningMode.EveryCodepoint)
return true;
// Don't stop in the middle of a grapheme
if (charAfter == CharacterClass.CombiningMark)
return false;
// Stop after every grapheme in normal mode
if (mode == CaretPositioningMode.Normal)
return true;
if (charBefore == charAfter) {
if (charBefore == CharacterClass.Other &&
(mode == CaretPositioningMode.WordBorderOrSymbol || mode == CaretPositioningMode.WordStartOrSymbol))
{
// With the "OrSymbol" modes, there's a word border and start between any two unknown characters
return true;
}
} else {
// this looks like a possible border
// if we're looking for word starts, check that this is a word start (and not a word end)
// if we're just checking for word borders, accept unconditionally
if (!((mode == CaretPositioningMode.WordStart || mode == CaretPositioningMode.WordStartOrSymbol)
&& (charAfter == CharacterClass.Whitespace || charAfter == CharacterClass.LineTerminator)))
{
return true;
}
}
return false;
}
#endregion
}
@ -327,6 +412,11 @@ namespace ICSharpCode.AvalonEdit.Document @@ -327,6 +412,11 @@ namespace ICSharpCode.AvalonEdit.Document
/// <summary>
/// The character is line terminator (\r or \n).
/// </summary>
LineTerminator
LineTerminator,
/// <summary>
/// The character is a unicode combining mark that modifies the previous character.
/// Corresponds to the Unicode designations "Mn", "Mc" and "Me".
/// </summary>
CombiningMark
}
}

19
AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoOperationGroup.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;

24
AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoStack.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
@ -193,7 +208,7 @@ namespace ICSharpCode.AvalonEdit.Document @@ -193,7 +208,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary>
/// <param name="groupDescriptor">An object that is stored with the undo group.
/// If this is not a top-level undo group, the parameter is ignored.</param>
public void StartContinuedUndoGroup(object groupDescriptor)
public void StartContinuedUndoGroup(object groupDescriptor = null)
{
if (undoGroupDepth == 0) {
actionCountInUndoGroup = (allowContinue && undostack.Count > 0) ? 1 : 0;
@ -214,11 +229,13 @@ namespace ICSharpCode.AvalonEdit.Document @@ -214,11 +229,13 @@ namespace ICSharpCode.AvalonEdit.Document
//Util.LoggingService.Debug("Close undo group (new depth=" + undoGroupDepth + ")");
if (undoGroupDepth == 0) {
Debug.Assert(state == StateListen || actionCountInUndoGroup == 0);
allowContinue = true;
if (actionCountInUndoGroup == optionalActionCount) {
// only optional actions: don't store them
for (int i = 0; i < optionalActionCount; i++) {
undostack.PopBack();
}
allowContinue = false;
} else if (actionCountInUndoGroup > 1) {
// combine all actions within the group into a single grouped action
undostack.PushBack(new UndoOperationGroup(undostack, actionCountInUndoGroup));
@ -226,7 +243,6 @@ namespace ICSharpCode.AvalonEdit.Document @@ -226,7 +243,6 @@ namespace ICSharpCode.AvalonEdit.Document
}
//if (state == StateListen) {
EnforceSizeLimit();
allowContinue = true;
RecalcIsOriginalFile(); // can raise event
//}
}

28
AvalonEdit/ICSharpCode.AvalonEdit/Document/WeakLineTracker.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
@ -81,5 +96,14 @@ namespace ICSharpCode.AvalonEdit.Document @@ -81,5 +96,14 @@ namespace ICSharpCode.AvalonEdit.Document
else
Deregister();
}
void ILineTracker.ChangeComplete(DocumentChangeEventArgs e)
{
ILineTracker targetTracker = targetObject.Target as ILineTracker;
if (targetTracker != null)
targetTracker.ChangeComplete(e);
else
Deregister();
}
}
}

19
AvalonEdit/ICSharpCode.AvalonEdit/Editing/AbstractMargin.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;

83
AvalonEdit/ICSharpCode.AvalonEdit/Editing/Caret.cs

@ -1,17 +1,36 @@ @@ -1,17 +1,36 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{
@ -31,12 +50,19 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -31,12 +50,19 @@ namespace ICSharpCode.AvalonEdit.Editing
this.textView = textArea.TextView;
position = new TextViewPosition(1, 1, 0);
caretAdorner = new CaretLayer(textView);
caretAdorner = new CaretLayer(textArea);
textView.InsertLayer(caretAdorner, KnownLayer.Caret, LayerInsertionPosition.Replace);
textView.VisualLinesChanged += TextView_VisualLinesChanged;
textView.ScrollOffsetChanged += TextView_ScrollOffsetChanged;
}
internal void UpdateIfVisible()
{
if (visible) {
Show();
}
}
void TextView_VisualLinesChanged(object sender, EventArgs e)
{
if (visible) {
@ -166,7 +192,14 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -166,7 +192,14 @@ namespace ICSharpCode.AvalonEdit.Editing
{
InvalidateVisualColumn();
if (storedCaretOffset >= 0) {
int newCaretOffset = e.GetNewOffset(storedCaretOffset, AnchorMovementType.Default);
// If the caret is at the end of a selection, we don't expand the selection if something
// is inserted at the end. Thus we also need to keep the caret in front of the insertion.
AnchorMovementType caretMovementType;
if (!textArea.Selection.IsEmpty && storedCaretOffset == textArea.Selection.SurroundingSegment.EndOffset)
caretMovementType = AnchorMovementType.BeforeInsertion;
else
caretMovementType = AnchorMovementType.Default;
int newCaretOffset = e.GetNewOffset(storedCaretOffset, caretMovementType);
TextDocument document = textArea.Document;
if (document != null) {
// keep visual column
@ -348,7 +381,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -348,7 +381,7 @@ namespace ICSharpCode.AvalonEdit.Editing
RevalidateVisualColumn(visualLine);
}
TextLine textLine = visualLine.GetTextLine(position.VisualColumn);
TextLine textLine = visualLine.GetTextLine(position.VisualColumn, position.IsAtEndOfLine);
double xPos = visualLine.GetTextLineVisualXPosition(textLine, position.VisualColumn);
double lineTop = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextTop);
double lineBottom = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextBottom);
@ -359,6 +392,39 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -359,6 +392,39 @@ namespace ICSharpCode.AvalonEdit.Editing
lineBottom - lineTop);
}
Rect CalcCaretOverstrikeRectangle(VisualLine visualLine)
{
if (!visualColumnValid) {
RevalidateVisualColumn(visualLine);
}
int currentPos = position.VisualColumn;
// The text being overwritten in overstrike mode is everything up to the next normal caret stop
int nextPos = visualLine.GetNextCaretPosition(currentPos, LogicalDirection.Forward, CaretPositioningMode.Normal, true);
TextLine textLine = visualLine.GetTextLine(currentPos);
Rect r;
if (currentPos < visualLine.VisualLength) {
// If the caret is within the text, use GetTextBounds() for the text being overwritten.
// This is necessary to ensure the rectangle is calculated correctly in bidirectional text.
var textBounds = textLine.GetTextBounds(currentPos, nextPos - currentPos)[0];
r = textBounds.Rectangle;
r.Y += visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineTop);
} else {
// If the caret is at the end of the line (or in virtual space),
// use the visual X position of currentPos and nextPos (one or more of which will be in virtual space)
double xPos = visualLine.GetTextLineVisualXPosition(textLine, currentPos);
double xPos2 = visualLine.GetTextLineVisualXPosition(textLine, nextPos);
double lineTop = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextTop);
double lineBottom = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.TextBottom);
r = new Rect(xPos, lineTop, xPos2 - xPos, lineBottom - lineTop);
}
// If the caret is too small (e.g. in front of zero-width character), ensure it's still visible
if (r.Width < SystemParameters.CaretWidth)
r.Width = SystemParameters.CaretWidth;
return r;
}
/// <summary>
/// Returns the caret rectangle. The coordinate system is in device-independent pixels from the top of the document.
/// </summary>
@ -366,7 +432,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -366,7 +432,7 @@ namespace ICSharpCode.AvalonEdit.Editing
{
if (textView != null && textView.Document != null) {
VisualLine visualLine = textView.GetOrConstructVisualLine(textView.Document.GetLineByNumber(position.Line));
return CalcCaretRectangle(visualLine);
return textArea.OverstrikeMode ? CalcCaretOverstrikeRectangle(visualLine) : CalcCaretRectangle(visualLine);
} else {
return Rect.Empty;
}
@ -421,7 +487,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -421,7 +487,7 @@ namespace ICSharpCode.AvalonEdit.Editing
if (caretAdorner != null && textView != null) {
VisualLine visualLine = textView.GetVisualLine(position.Line);
if (visualLine != null) {
Rect caretRect = CalcCaretRectangle(visualLine);
Rect caretRect = this.textArea.OverstrikeMode ? CalcCaretOverstrikeRectangle(visualLine) : CalcCaretRectangle(visualLine);
// Create Win32 caret so that Windows knows where our managed caret is. This is necessary for
// features like 'Follow text editing' in the Windows Magnifier.
if (!hasWin32Caret) {
@ -431,6 +497,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -431,6 +497,7 @@ namespace ICSharpCode.AvalonEdit.Editing
Win32.SetCaretPosition(textView, caretRect.Location - textView.ScrollOffset);
}
caretAdorner.Show(caretRect);
textArea.ime.UpdateCompositionWindow();
} else {
caretAdorner.Hide();
}

35
AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretLayer.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
@ -15,14 +30,17 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -15,14 +30,17 @@ namespace ICSharpCode.AvalonEdit.Editing
{
sealed class CaretLayer : Layer
{
TextArea textArea;
bool isVisible;
Rect caretRectangle;
DispatcherTimer caretBlinkTimer = new DispatcherTimer();
bool blink;
public CaretLayer(TextView textView) : base(textView, KnownLayer.Caret)
public CaretLayer(TextArea textArea) : base(textArea.TextView, KnownLayer.Caret)
{
this.textArea = textArea;
this.IsHitTestVisible = false;
caretBlinkTimer.Tick += new EventHandler(caretBlinkTimer_Tick);
}
@ -75,6 +93,17 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -75,6 +93,17 @@ namespace ICSharpCode.AvalonEdit.Editing
Brush caretBrush = this.CaretBrush;
if (caretBrush == null)
caretBrush = (Brush)textView.GetValue(TextBlock.ForegroundProperty);
if (this.textArea.OverstrikeMode) {
SolidColorBrush scBrush = caretBrush as SolidColorBrush;
if (scBrush != null) {
Color brushColor = scBrush.Color;
Color newColor = Color.FromArgb(100, brushColor.R, brushColor.G, brushColor.B);
caretBrush = new SolidColorBrush(newColor);
caretBrush.Freeze();
}
}
Rect r = new Rect(caretRectangle.X - textView.HorizontalOffset,
caretRectangle.Y - textView.VerticalOffset,
caretRectangle.Width,

257
AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs

@ -1,9 +1,25 @@ @@ -1,9 +1,25 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
@ -14,6 +30,24 @@ using ICSharpCode.AvalonEdit.Utils; @@ -14,6 +30,24 @@ using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Editing
{
enum CaretMovementType
{
None,
CharLeft,
CharRight,
Backspace,
WordLeft,
WordRight,
LineUp,
LineDown,
PageUp,
PageDown,
LineStart,
LineEnd,
DocumentStart,
DocumentEnd
}
static class CaretNavigationCommandHandler
{
/// <summary>
@ -41,21 +75,28 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -41,21 +75,28 @@ namespace ICSharpCode.AvalonEdit.Editing
const ModifierKeys None = ModifierKeys.None;
const ModifierKeys Ctrl = ModifierKeys.Control;
const ModifierKeys Shift = ModifierKeys.Shift;
const ModifierKeys Alt = ModifierKeys.Alt;
AddBinding(EditingCommands.MoveLeftByCharacter, None, Key.Left, OnMoveCaret(CaretMovementType.CharLeft));
AddBinding(EditingCommands.SelectLeftByCharacter, Shift, Key.Left, OnMoveCaretExtendSelection(CaretMovementType.CharLeft));
AddBinding(RectangleSelection.BoxSelectLeftByCharacter, Alt | Shift, Key.Left, OnMoveCaretBoxSelection(CaretMovementType.CharLeft));
AddBinding(EditingCommands.MoveRightByCharacter, None, Key.Right, OnMoveCaret(CaretMovementType.CharRight));
AddBinding(EditingCommands.SelectRightByCharacter, Shift, Key.Right, OnMoveCaretExtendSelection(CaretMovementType.CharRight));
AddBinding(RectangleSelection.BoxSelectRightByCharacter, Alt | Shift, Key.Right, OnMoveCaretBoxSelection(CaretMovementType.CharRight));
AddBinding(EditingCommands.MoveLeftByWord, Ctrl, Key.Left, OnMoveCaret(CaretMovementType.WordLeft));
AddBinding(EditingCommands.SelectLeftByWord, Ctrl | Shift, Key.Left, OnMoveCaretExtendSelection(CaretMovementType.WordLeft));
AddBinding(RectangleSelection.BoxSelectLeftByWord, Ctrl | Alt | Shift, Key.Left, OnMoveCaretBoxSelection(CaretMovementType.WordLeft));
AddBinding(EditingCommands.MoveRightByWord, Ctrl, Key.Right, OnMoveCaret(CaretMovementType.WordRight));
AddBinding(EditingCommands.SelectRightByWord, Ctrl | Shift, Key.Right, OnMoveCaretExtendSelection(CaretMovementType.WordRight));
AddBinding(RectangleSelection.BoxSelectRightByWord, Ctrl | Alt | Shift, Key.Right, OnMoveCaretBoxSelection(CaretMovementType.WordRight));
AddBinding(EditingCommands.MoveUpByLine, None, Key.Up, OnMoveCaret(CaretMovementType.LineUp));
AddBinding(EditingCommands.SelectUpByLine, Shift, Key.Up, OnMoveCaretExtendSelection(CaretMovementType.LineUp));
AddBinding(RectangleSelection.BoxSelectUpByLine, Alt | Shift, Key.Up, OnMoveCaretBoxSelection(CaretMovementType.LineUp));
AddBinding(EditingCommands.MoveDownByLine, None, Key.Down, OnMoveCaret(CaretMovementType.LineDown));
AddBinding(EditingCommands.SelectDownByLine, Shift, Key.Down, OnMoveCaretExtendSelection(CaretMovementType.LineDown));
AddBinding(RectangleSelection.BoxSelectDownByLine, Alt | Shift, Key.Down, OnMoveCaretBoxSelection(CaretMovementType.LineDown));
AddBinding(EditingCommands.MoveDownByPage, None, Key.PageDown, OnMoveCaret(CaretMovementType.PageDown));
AddBinding(EditingCommands.SelectDownByPage, Shift, Key.PageDown, OnMoveCaretExtendSelection(CaretMovementType.PageDown));
@ -64,8 +105,10 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -64,8 +105,10 @@ namespace ICSharpCode.AvalonEdit.Editing
AddBinding(EditingCommands.MoveToLineStart, None, Key.Home, OnMoveCaret(CaretMovementType.LineStart));
AddBinding(EditingCommands.SelectToLineStart, Shift, Key.Home, OnMoveCaretExtendSelection(CaretMovementType.LineStart));
AddBinding(RectangleSelection.BoxSelectToLineStart, Alt | Shift, Key.Home, OnMoveCaretBoxSelection(CaretMovementType.LineStart));
AddBinding(EditingCommands.MoveToLineEnd, None, Key.End, OnMoveCaret(CaretMovementType.LineEnd));
AddBinding(EditingCommands.SelectToLineEnd, Shift, Key.End, OnMoveCaretExtendSelection(CaretMovementType.LineEnd));
AddBinding(RectangleSelection.BoxSelectToLineEnd, Alt | Shift, Key.End, OnMoveCaretBoxSelection(CaretMovementType.LineEnd));
AddBinding(EditingCommands.MoveToDocumentStart, Ctrl, Key.Home, OnMoveCaret(CaretMovementType.DocumentStart));
AddBinding(EditingCommands.SelectToDocumentStart, Ctrl | Shift, Key.Home, OnMoveCaretExtendSelection(CaretMovementType.DocumentStart));
@ -92,22 +135,6 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -92,22 +135,6 @@ namespace ICSharpCode.AvalonEdit.Editing
return target as TextArea;
}
enum CaretMovementType
{
CharLeft,
CharRight,
WordLeft,
WordRight,
LineUp,
LineDown,
PageUp,
PageDown,
LineStart,
LineEnd,
DocumentStart,
DocumentEnd
}
static ExecutedRoutedEventHandler OnMoveCaret(CaretMovementType direction)
{
return (target, args) => {
@ -135,44 +162,81 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -135,44 +162,81 @@ namespace ICSharpCode.AvalonEdit.Editing
};
}
static ExecutedRoutedEventHandler OnMoveCaretBoxSelection(CaretMovementType direction)
{
return (target, args) => {
TextArea textArea = GetTextArea(target);
if (textArea != null && textArea.Document != null) {
args.Handled = true;
// First, convert the selection into a rectangle selection
// (this is required so that virtual space gets enabled for the caret movement)
if (textArea.Options.EnableRectangularSelection && !(textArea.Selection is RectangleSelection)) {
if (textArea.Selection.IsEmpty) {
textArea.Selection = new RectangleSelection(textArea, textArea.Caret.Position, textArea.Caret.Position);
} else {
// Convert normal selection to rectangle selection
textArea.Selection = new RectangleSelection(textArea, textArea.Selection.StartPosition, textArea.Caret.Position);
}
}
// Now move the caret and extend the selection
TextViewPosition oldPosition = textArea.Caret.Position;
MoveCaret(textArea, direction);
textArea.Selection = textArea.Selection.StartSelectionOrSetEndpoint(oldPosition, textArea.Caret.Position);
textArea.Caret.BringCaretToView();
}
};
}
#region Caret movement
static void MoveCaret(TextArea textArea, CaretMovementType direction)
internal static void MoveCaret(TextArea textArea, CaretMovementType direction)
{
DocumentLine caretLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(caretLine);
TextViewPosition caretPosition = textArea.Caret.Position;
TextLine textLine = visualLine.GetTextLine(caretPosition.VisualColumn);
double desiredXPos = textArea.Caret.DesiredXPos;
textArea.Caret.Position = GetNewCaretPosition(textArea.TextView, textArea.Caret.Position, direction, textArea.Selection.EnableVirtualSpace, ref desiredXPos);
textArea.Caret.DesiredXPos = desiredXPos;
}
internal static TextViewPosition GetNewCaretPosition(TextView textView, TextViewPosition caretPosition, CaretMovementType direction, bool enableVirtualSpace, ref double desiredXPos)
{
switch (direction) {
case CaretMovementType.None:
return caretPosition;
case CaretMovementType.DocumentStart:
desiredXPos = double.NaN;
return new TextViewPosition(0, 0);
case CaretMovementType.DocumentEnd:
desiredXPos = double.NaN;
return new TextViewPosition(textView.Document.GetLocation(textView.Document.TextLength));
}
DocumentLine caretLine = textView.Document.GetLineByNumber(caretPosition.Line);
VisualLine visualLine = textView.GetOrConstructVisualLine(caretLine);
TextLine textLine = visualLine.GetTextLine(caretPosition.VisualColumn, caretPosition.IsAtEndOfLine);
switch (direction) {
case CaretMovementType.CharLeft:
MoveCaretLeft(textArea, caretPosition, visualLine, CaretPositioningMode.Normal);
break;
desiredXPos = double.NaN;
return GetPrevCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.Normal, enableVirtualSpace);
case CaretMovementType.Backspace:
desiredXPos = double.NaN;
return GetPrevCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.EveryCodepoint, enableVirtualSpace);
case CaretMovementType.CharRight:
MoveCaretRight(textArea, caretPosition, visualLine, CaretPositioningMode.Normal);
break;
desiredXPos = double.NaN;
return GetNextCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.Normal, enableVirtualSpace);
case CaretMovementType.WordLeft:
MoveCaretLeft(textArea, caretPosition, visualLine, CaretPositioningMode.WordStart);
break;
desiredXPos = double.NaN;
return GetPrevCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.WordStart, enableVirtualSpace);
case CaretMovementType.WordRight:
MoveCaretRight(textArea, caretPosition, visualLine, CaretPositioningMode.WordStart);
break;
desiredXPos = double.NaN;
return GetNextCaretPosition(textView, caretPosition, visualLine, CaretPositioningMode.WordStart, enableVirtualSpace);
case CaretMovementType.LineUp:
case CaretMovementType.LineDown:
case CaretMovementType.PageUp:
case CaretMovementType.PageDown:
MoveCaretUpDown(textArea, direction, visualLine, textLine, caretPosition.VisualColumn);
break;
case CaretMovementType.DocumentStart:
SetCaretPosition(textArea, 0, 0);
break;
case CaretMovementType.DocumentEnd:
SetCaretPosition(textArea, -1, textArea.Document.TextLength);
break;
return GetUpDownCaretPosition(textView, caretPosition, direction, visualLine, textLine, enableVirtualSpace, ref desiredXPos);
case CaretMovementType.LineStart:
MoveCaretToStartOfLine(textArea, visualLine);
break;
desiredXPos = double.NaN;
return GetStartOfLineCaretPosition(caretPosition.VisualColumn, visualLine, textLine, enableVirtualSpace);
case CaretMovementType.LineEnd:
MoveCaretToEndOfLine(textArea, visualLine);
break;
desiredXPos = double.NaN;
return GetEndOfLineCaretPosition(visualLine, textLine);
default:
throw new NotSupportedException(direction.ToString());
}
@ -180,79 +244,80 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -180,79 +244,80 @@ namespace ICSharpCode.AvalonEdit.Editing
#endregion
#region Home/End
static void MoveCaretToStartOfLine(TextArea textArea, VisualLine visualLine)
static TextViewPosition GetStartOfLineCaretPosition(int oldVC, VisualLine visualLine, TextLine textLine, bool enableVirtualSpace)
{
int newVC = visualLine.GetNextCaretPosition(-1, LogicalDirection.Forward, CaretPositioningMode.WordStart, textArea.Selection.EnableVirtualSpace);
int newVC = visualLine.GetTextLineVisualStartColumn(textLine);
if (newVC == 0)
newVC = visualLine.GetNextCaretPosition(newVC - 1, LogicalDirection.Forward, CaretPositioningMode.WordStart, enableVirtualSpace);
if (newVC < 0)
throw ThrowUtil.NoValidCaretPosition();
// when the caret is already at the start of the text, jump to start before whitespace
if (newVC == textArea.Caret.VisualColumn)
if (newVC == oldVC)
newVC = 0;
int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC);
SetCaretPosition(textArea, newVC, offset);
return visualLine.GetTextViewPosition(newVC);
}
static void MoveCaretToEndOfLine(TextArea textArea, VisualLine visualLine)
static TextViewPosition GetEndOfLineCaretPosition(VisualLine visualLine, TextLine textLine)
{
int newVC = visualLine.VisualLength;
int offset = visualLine.FirstDocumentLine.Offset + visualLine.GetRelativeOffset(newVC);
SetCaretPosition(textArea, newVC, offset);
int newVC = visualLine.GetTextLineVisualStartColumn(textLine) + textLine.Length - textLine.TrailingWhitespaceLength;
TextViewPosition pos = visualLine.GetTextViewPosition(newVC);
pos.IsAtEndOfLine = true;
return pos;
}
#endregion
#region By-character / By-word movement
static void MoveCaretRight(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode)
static TextViewPosition GetNextCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
{
int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace);
int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Forward, mode, enableVirtualSpace);
if (pos >= 0) {
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
return visualLine.GetTextViewPosition(pos);
} else {
// move to start of next line
DocumentLine nextDocumentLine = visualLine.LastDocumentLine.NextLine;
if (nextDocumentLine != null) {
VisualLine nextLine = textArea.TextView.GetOrConstructVisualLine(nextDocumentLine);
pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, textArea.Selection.EnableVirtualSpace);
VisualLine nextLine = textView.GetOrConstructVisualLine(nextDocumentLine);
pos = nextLine.GetNextCaretPosition(-1, LogicalDirection.Forward, mode, enableVirtualSpace);
if (pos < 0)
throw ThrowUtil.NoValidCaretPosition();
SetCaretPosition(textArea, pos, nextLine.GetRelativeOffset(pos) + nextLine.FirstDocumentLine.Offset);
return nextLine.GetTextViewPosition(pos);
} else {
// at end of document
Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textArea.Document.TextLength);
SetCaretPosition(textArea, -1, textArea.Document.TextLength);
Debug.Assert(visualLine.LastDocumentLine.Offset + visualLine.LastDocumentLine.TotalLength == textView.Document.TextLength);
return new TextViewPosition(textView.Document.GetLocation(textView.Document.TextLength));
}
}
}
static void MoveCaretLeft(TextArea textArea, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode)
static TextViewPosition GetPrevCaretPosition(TextView textView, TextViewPosition caretPosition, VisualLine visualLine, CaretPositioningMode mode, bool enableVirtualSpace)
{
int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace);
int pos = visualLine.GetNextCaretPosition(caretPosition.VisualColumn, LogicalDirection.Backward, mode, enableVirtualSpace);
if (pos >= 0) {
SetCaretPosition(textArea, pos, visualLine.GetRelativeOffset(pos) + visualLine.FirstDocumentLine.Offset);
return visualLine.GetTextViewPosition(pos);
} else {
// move to end of previous line
DocumentLine previousDocumentLine = visualLine.FirstDocumentLine.PreviousLine;
if (previousDocumentLine != null) {
VisualLine previousLine = textArea.TextView.GetOrConstructVisualLine(previousDocumentLine);
pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, textArea.Selection.EnableVirtualSpace);
VisualLine previousLine = textView.GetOrConstructVisualLine(previousDocumentLine);
pos = previousLine.GetNextCaretPosition(previousLine.VisualLength + 1, LogicalDirection.Backward, mode, enableVirtualSpace);
if (pos < 0)
throw ThrowUtil.NoValidCaretPosition();
SetCaretPosition(textArea, pos, previousLine.GetRelativeOffset(pos) + previousLine.FirstDocumentLine.Offset);
return previousLine.GetTextViewPosition(pos);
} else {
// at start of document
Debug.Assert(visualLine.FirstDocumentLine.Offset == 0);
SetCaretPosition(textArea, 0, 0);
return new TextViewPosition(0, 0);
}
}
}
#endregion
#region Line+Page up/down
static void MoveCaretUpDown(TextArea textArea, CaretMovementType direction, VisualLine visualLine, TextLine textLine, int caretVisualColumn)
static TextViewPosition GetUpDownCaretPosition(TextView textView, TextViewPosition caretPosition, CaretMovementType direction, VisualLine visualLine, TextLine textLine, bool enableVirtualSpace, ref double xPos)
{
// moving up/down happens using the desired visual X position
double xPos = textArea.Caret.DesiredXPos;
if (double.IsNaN(xPos))
xPos = visualLine.GetTextLineVisualXPosition(textLine, caretVisualColumn);
xPos = visualLine.GetTextLineVisualXPosition(textLine, caretPosition.VisualColumn);
// now find the TextLine+VisualLine where the caret will end up in
VisualLine targetVisualLine = visualLine;
TextLine targetLine;
@ -266,8 +331,8 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -266,8 +331,8 @@ namespace ICSharpCode.AvalonEdit.Editing
if (textLineIndex > 0) {
targetLine = visualLine.TextLines[textLineIndex - 1];
} else if (prevLineNumber >= 1) {
DocumentLine prevLine = textArea.Document.GetLineByNumber(prevLineNumber);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(prevLine);
DocumentLine prevLine = textView.Document.GetLineByNumber(prevLineNumber);
targetVisualLine = textView.GetOrConstructVisualLine(prevLine);
targetLine = targetVisualLine.TextLines[targetVisualLine.TextLines.Count - 1];
} else {
targetLine = null;
@ -281,9 +346,9 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -281,9 +346,9 @@ namespace ICSharpCode.AvalonEdit.Editing
int nextLineNumber = visualLine.LastDocumentLine.LineNumber + 1;
if (textLineIndex < visualLine.TextLines.Count - 1) {
targetLine = visualLine.TextLines[textLineIndex + 1];
} else if (nextLineNumber <= textArea.Document.LineCount) {
DocumentLine nextLine = textArea.Document.GetLineByNumber(nextLineNumber);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(nextLine);
} else if (nextLineNumber <= textView.Document.LineCount) {
DocumentLine nextLine = textView.Document.GetLineByNumber(nextLineNumber);
targetVisualLine = textView.GetOrConstructVisualLine(nextLine);
targetLine = targetVisualLine.TextLines[0];
} else {
targetLine = null;
@ -296,11 +361,11 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -296,11 +361,11 @@ namespace ICSharpCode.AvalonEdit.Editing
// Page up/down: find the target line using its visual position
double yPos = visualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineMiddle);
if (direction == CaretMovementType.PageUp)
yPos -= textArea.TextView.RenderSize.Height;
yPos -= textView.RenderSize.Height;
else
yPos += textArea.TextView.RenderSize.Height;
DocumentLine newLine = textArea.TextView.GetDocumentLineByVisualTop(yPos);
targetVisualLine = textArea.TextView.GetOrConstructVisualLine(newLine);
yPos += textView.RenderSize.Height;
DocumentLine newLine = textView.GetDocumentLineByVisualTop(yPos);
targetVisualLine = textView.GetOrConstructVisualLine(newLine);
targetLine = targetVisualLine.GetTextLineByVisualYPosition(yPos);
break;
}
@ -309,30 +374,18 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -309,30 +374,18 @@ namespace ICSharpCode.AvalonEdit.Editing
}
if (targetLine != null) {
double yPos = targetVisualLine.GetTextLineVisualYPosition(targetLine, VisualYPosition.LineMiddle);
int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), textArea.Selection.EnableVirtualSpace);
SetCaretPosition(textArea, targetVisualLine, targetLine, newVisualColumn, false);
textArea.Caret.DesiredXPos = xPos;
}
}
#endregion
#region SetCaretPosition
static void SetCaretPosition(TextArea textArea, VisualLine targetVisualLine, TextLine targetLine,
int newVisualColumn, bool allowWrapToNextLine)
{
int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine);
if (!allowWrapToNextLine && newVisualColumn >= targetLineStartCol + targetLine.Length) {
if (newVisualColumn <= targetVisualLine.VisualLength)
newVisualColumn = targetLineStartCol + targetLine.Length - 1;
int newVisualColumn = targetVisualLine.GetVisualColumn(new Point(xPos, yPos), enableVirtualSpace);
// prevent wrapping to the next line; TODO: could 'IsAtEnd' help here?
int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine);
if (newVisualColumn >= targetLineStartCol + targetLine.Length) {
if (newVisualColumn <= targetVisualLine.VisualLength)
newVisualColumn = targetLineStartCol + targetLine.Length - 1;
}
return targetVisualLine.GetTextViewPosition(newVisualColumn);
} else {
return caretPosition;
}
int newOffset = targetVisualLine.GetRelativeOffset(newVisualColumn) + targetVisualLine.FirstDocumentLine.Offset;
SetCaretPosition(textArea, newVisualColumn, newOffset);
}
static void SetCaretPosition(TextArea textArea, int newVisualColumn, int newOffset)
{
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(newOffset), newVisualColumn);
textArea.Caret.DesiredXPos = double.NaN;
}
#endregion
}

19
AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretWeakEventHandler.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.AvalonEdit.Utils;
using System;

19
AvalonEdit/ICSharpCode.AvalonEdit/Editing/DottedLineMargin.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;

19
AvalonEdit/ICSharpCode.AvalonEdit/Editing/DragDropException.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Runtime.Serialization;

172
AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
@ -8,14 +23,15 @@ using System.Globalization; @@ -8,14 +23,15 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Search;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{
@ -47,12 +63,12 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -47,12 +63,12 @@ namespace ICSharpCode.AvalonEdit.Editing
static EditingCommandHandler()
{
CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete, OnDelete(ApplicationCommands.NotACommand), CanDelete));
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));
CommandBindings.Add(new CommandBinding(ApplicationCommands.Delete, OnDelete(CaretMovementType.None), CanDelete));
AddBinding(EditingCommands.Delete, ModifierKeys.None, Key.Delete, OnDelete(CaretMovementType.CharRight));
AddBinding(EditingCommands.DeleteNextWord, ModifierKeys.Control, Key.Delete, OnDelete(CaretMovementType.WordRight));
AddBinding(EditingCommands.Backspace, ModifierKeys.None, Key.Back, OnDelete(CaretMovementType.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.DeletePreviousWord, ModifierKeys.Control, Key.Back, OnDelete(CaretMovementType.WordLeft));
AddBinding(EditingCommands.EnterParagraphBreak, ModifierKeys.None, Key.Enter, OnEnter);
AddBinding(EditingCommands.EnterLineBreak, ModifierKeys.Shift, Key.Enter, OnEnter);
AddBinding(EditingCommands.TabForward, ModifierKeys.None, Key.Tab, OnTab);
@ -226,34 +242,28 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -226,34 +242,28 @@ namespace ICSharpCode.AvalonEdit.Editing
#endregion
#region Delete
static ExecutedRoutedEventHandler OnDelete(RoutedUICommand selectingCommand)
static ExecutedRoutedEventHandler OnDelete(CaretMovementType caretMovement)
{
return (target, args) => {
TextArea textArea = GetTextArea(target);
if (textArea != null && textArea.Document != null) {
// call BeginUpdate before running the 'selectingCommand'
// so that undoing the delete does not select the deleted character
using (textArea.Document.RunUpdate()) {
if (textArea.Selection.IsEmpty) {
TextViewPosition oldCaretPosition = textArea.Caret.Position;
if (textArea.Caret.IsInVirtualSpace && selectingCommand == EditingCommands.SelectRightByCharacter)
EditingCommands.SelectRightByWord.Execute(args.Parameter, textArea);
else
selectingCommand.Execute(args.Parameter, textArea);
bool hasSomethingDeletable = false;
foreach (ISegment s in textArea.Selection.Segments) {
if (textArea.GetDeletableSegments(s).Length > 0) {
hasSomethingDeletable = true;
break;
}
}
if (!hasSomethingDeletable) {
// If nothing in the selection is deletable; then reset caret+selection
// to the previous value. This prevents the caret from moving through read-only sections.
textArea.Caret.Position = oldCaretPosition;
textArea.ClearSelection();
}
}
if (textArea.Selection.IsEmpty) {
TextViewPosition startPos = textArea.Caret.Position;
bool enableVirtualSpace = textArea.Options.EnableVirtualSpace;
// When pressing delete; don't move the caret further into virtual space - instead delete the newline
if (caretMovement == CaretMovementType.CharRight)
enableVirtualSpace = false;
double desiredXPos = textArea.Caret.DesiredXPos;
TextViewPosition endPos = CaretNavigationCommandHandler.GetNewCaretPosition(
textArea.TextView, startPos, caretMovement, enableVirtualSpace, ref desiredXPos);
// GetNewCaretPosition may return (0,0) as new position,
// thus we need to validate endPos before using it in the selection.
if (endPos.Line < 1 || endPos.Column < 1)
endPos = new TextViewPosition(Math.Max(endPos.Line, 1), Math.Max(endPos.Column, 1));
// Don't select the text to be deleted; just reuse the ReplaceSelectionWithText logic
var sel = new SimpleSelection(textArea, startPos, endPos);
sel.ReplaceSelectionWithText(string.Empty);
} else {
textArea.RemoveSelectedText();
}
textArea.Caret.BringCaretToView();
@ -304,64 +314,88 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -304,64 +314,88 @@ namespace ICSharpCode.AvalonEdit.Editing
if (textArea != null && textArea.Document != null) {
if (textArea.Selection.IsEmpty && textArea.Options.CutCopyWholeLine) {
DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
CopyWholeLine(textArea, currentLine);
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(new SimpleSegment(currentLine.Offset, currentLine.TotalLength));
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
textArea.Document.Remove(segmentsToDelete[i]);
if (CopyWholeLine(textArea, currentLine)) {
ISegment[] segmentsToDelete = textArea.GetDeletableSegments(new SimpleSegment(currentLine.Offset, currentLine.TotalLength));
for (int i = segmentsToDelete.Length - 1; i >= 0; i--) {
textArea.Document.Remove(segmentsToDelete[i]);
}
}
} else {
CopySelectedText(textArea);
textArea.RemoveSelectedText();
if (CopySelectedText(textArea))
textArea.RemoveSelectedText();
}
textArea.Caret.BringCaretToView();
args.Handled = true;
}
}
static void CopySelectedText(TextArea textArea)
static bool CopySelectedText(TextArea textArea)
{
var data = textArea.Selection.CreateDataObject(textArea);
var copyingEventArgs = new DataObjectCopyingEventArgs(data, false);
textArea.RaiseEvent(copyingEventArgs);
if (copyingEventArgs.CommandCancelled)
return false;
try {
Clipboard.SetDataObject(data, true);
} catch (ExternalException) {
// Apparently this exception sometimes happens randomly.
// The MS controls just ignore it, so we'll do the same.
return;
}
string text = textArea.Selection.GetText();
text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
textArea.OnTextCopied(new TextEventArgs(text));
return true;
}
const string LineSelectedType = "MSDEVLineSelect"; // This is the type VS 2003 and 2005 use for flagging a whole line copy
static void CopyWholeLine(TextArea textArea, DocumentLine line)
public static bool ConfirmDataFormat(TextArea textArea, DataObject dataObject, string format)
{
var e = new DataObjectSettingDataEventArgs(dataObject, format);
textArea.RaiseEvent(e);
return !e.CommandCancelled;
}
static bool CopyWholeLine(TextArea textArea, DocumentLine line)
{
ISegment wholeLine = new SimpleSegment(line.Offset, line.TotalLength);
string text = textArea.Document.GetText(wholeLine);
// Ensure we use the appropriate newline sequence for the OS
text = TextUtilities.NormalizeNewLines(text, Environment.NewLine);
DataObject data = new DataObject(text);
DataObject data = new DataObject();
if (ConfirmDataFormat(textArea, data, DataFormats.UnicodeText))
data.SetText(text);
// Also copy text in HTML format to clipboard - good for pasting text into Word
// or to the SharpDevelop forums.
IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter;
HtmlClipboard.SetHtml(data, HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, wholeLine, new HtmlOptions(textArea.Options)));
if (ConfirmDataFormat(textArea, data, DataFormats.Html)) {
IHighlighter highlighter = textArea.GetService(typeof(IHighlighter)) as IHighlighter;
HtmlClipboard.SetHtml(data, HtmlClipboard.CreateHtmlFragment(textArea.Document, highlighter, wholeLine, new HtmlOptions(textArea.Options)));
}
if (ConfirmDataFormat(textArea, data, LineSelectedType)) {
MemoryStream lineSelected = new MemoryStream(1);
lineSelected.WriteByte(1);
data.SetData(LineSelectedType, lineSelected, false);
}
MemoryStream lineSelected = new MemoryStream(1);
lineSelected.WriteByte(1);
data.SetData(LineSelectedType, lineSelected, false);
var copyingEventArgs = new DataObjectCopyingEventArgs(data, false);
textArea.RaiseEvent(copyingEventArgs);
if (copyingEventArgs.CommandCancelled)
return false;
try {
Clipboard.SetDataObject(data, true);
} catch (ExternalException) {
// Apparently this exception sometimes happens randomly.
// The MS controls just ignore it, so we'll do the same.
return;
return false;
}
textArea.OnTextCopied(new TextEventArgs(text));
return true;
}
static void CanPaste(object target, CanExecuteRoutedEventArgs args)
@ -388,21 +422,43 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -388,21 +422,43 @@ namespace ICSharpCode.AvalonEdit.Editing
}
if (dataObject == null)
return;
Debug.WriteLine( dataObject.GetData(DataFormats.Html) as string );
var pastingEventArgs = new DataObjectPastingEventArgs(dataObject, false, DataFormats.UnicodeText);
textArea.RaiseEvent(pastingEventArgs);
if (pastingEventArgs.CommandCancelled)
return;
dataObject = pastingEventArgs.DataObject;
if (dataObject == null)
return;
// convert text back to correct newlines for this document
string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
string text;
try {
text = (string)dataObject.GetData(DataFormats.UnicodeText);
// Try retrieving the text as one of:
// - the FormatToApply
// - UnicodeText
// - Text
// (but don't try the same format twice)
if (pastingEventArgs.FormatToApply != null && dataObject.GetDataPresent(pastingEventArgs.FormatToApply))
text = (string)dataObject.GetData(pastingEventArgs.FormatToApply);
else if (pastingEventArgs.FormatToApply != DataFormats.UnicodeText && dataObject.GetDataPresent(DataFormats.UnicodeText))
text = (string)dataObject.GetData(DataFormats.UnicodeText);
else if (pastingEventArgs.FormatToApply != DataFormats.Text && dataObject.GetDataPresent(DataFormats.Text))
text = (string)dataObject.GetData(DataFormats.Text);
else
return; // no text data format
text = TextUtilities.NormalizeNewLines(text, newLine);
} catch (OutOfMemoryException) {
// may happen when trying to paste a huge string
return;
}
if (!string.IsNullOrEmpty(text)) {
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)) {
@ -426,8 +482,18 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -426,8 +482,18 @@ namespace ICSharpCode.AvalonEdit.Editing
{
TextArea textArea = GetTextArea(target);
if (textArea != null && textArea.Document != null) {
DocumentLine currentLine = textArea.Document.GetLineByNumber(textArea.Caret.Line);
textArea.Selection = Selection.Create(textArea, currentLine.Offset, currentLine.Offset + currentLine.TotalLength);
int firstLineIndex, lastLineIndex;
if (textArea.Selection.Length == 0) {
// There is no selection, simply delete current line
firstLineIndex = lastLineIndex = textArea.Caret.Line;
} else {
// There is a selection, remove all lines affected by it (use Min/Max to be independent from selection direction)
firstLineIndex = Math.Min(textArea.Selection.StartPosition.Line, textArea.Selection.EndPosition.Line);
lastLineIndex = Math.Max(textArea.Selection.StartPosition.Line, textArea.Selection.EndPosition.Line);
}
DocumentLine startLine = textArea.Document.GetLineByNumber(firstLineIndex);
DocumentLine endLine = textArea.Document.GetLineByNumber(lastLineIndex);
textArea.Selection = Selection.Create(textArea, startLine.Offset, endLine.Offset + endLine.TotalLength);
textArea.RemoveSelectedText();
args.Handled = true;
}

32
AvalonEdit/ICSharpCode.AvalonEdit/Editing/EmptySelection.cs

@ -1,11 +1,31 @@ @@ -1,11 +1,31 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{
@ -20,6 +40,14 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -20,6 +40,14 @@ namespace ICSharpCode.AvalonEdit.Editing
return this;
}
public override TextViewPosition StartPosition {
get { return new TextViewPosition(TextLocation.Empty); }
}
public override TextViewPosition EndPosition {
get { return new TextViewPosition(TextLocation.Empty); }
}
public override ISegment SurroundingSegment {
get { return null; }
}

23
AvalonEdit/ICSharpCode.AvalonEdit/Editing/IReadOnlySectionProvider.cs

@ -1,9 +1,28 @@ @@ -1,9 +1,28 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#else
using ICSharpCode.AvalonEdit.Document;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{

221
AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeNativeWrapper.cs

@ -0,0 +1,221 @@ @@ -0,0 +1,221 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
using Draw = System.Drawing;
namespace ICSharpCode.AvalonEdit.Editing
{
/// <summary>
/// Native API required for IME support.
/// </summary>
static class ImeNativeWrapper
{
[StructLayout(LayoutKind.Sequential)]
struct CompositionForm
{
public int dwStyle;
public POINT ptCurrentPos;
public RECT rcArea;
}
[StructLayout(LayoutKind.Sequential)]
struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct LOGFONT
{
public int lfHeight;
public int lfWidth;
public int lfEscapement;
public int lfOrientation;
public int lfWeight;
public byte lfItalic;
public byte lfUnderline;
public byte lfStrikeOut;
public byte lfCharSet;
public byte lfOutPrecision;
public byte lfClipPrecision;
public byte lfQuality;
public byte lfPitchAndFamily;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)] public string lfFaceName;
}
const int CPS_CANCEL = 0x4;
const int NI_COMPOSITIONSTR = 0x15;
const int GCS_COMPSTR = 0x0008;
public const int WM_IME_COMPOSITION = 0x10F;
public const int WM_IME_SETCONTEXT = 0x281;
public const int WM_INPUTLANGCHANGE = 0x51;
[DllImport("imm32.dll")]
public static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
[DllImport("imm32.dll")]
internal static extern IntPtr ImmGetContext(IntPtr hWnd);
[DllImport("imm32.dll")]
internal static extern IntPtr ImmGetDefaultIMEWnd(IntPtr hWnd);
[DllImport("imm32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
[DllImport("imm32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ImmNotifyIME(IntPtr hIMC, int dwAction, int dwIndex, int dwValue = 0);
[DllImport("imm32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ImmSetCompositionWindow(IntPtr hIMC, ref CompositionForm form);
[DllImport("imm32.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ImmSetCompositionFont(IntPtr hIMC, ref LOGFONT font);
[DllImport("imm32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ImmGetCompositionFont(IntPtr hIMC, out LOGFONT font);
[DllImport("msctf.dll")]
static extern int TF_CreateThreadMgr(out ITfThreadMgr threadMgr);
[ThreadStatic] static bool textFrameworkThreadMgrInitialized;
[ThreadStatic] static ITfThreadMgr textFrameworkThreadMgr;
public static ITfThreadMgr GetTextFrameworkThreadManager()
{
if (!textFrameworkThreadMgrInitialized) {
textFrameworkThreadMgrInitialized = true;
TF_CreateThreadMgr(out textFrameworkThreadMgr);
}
return textFrameworkThreadMgr;
}
public static bool NotifyIme(IntPtr hIMC)
{
return ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL);
}
public static bool SetCompositionWindow(HwndSource source, IntPtr hIMC, TextArea textArea)
{
if (textArea == null)
throw new ArgumentNullException("textArea");
Rect textViewBounds = textArea.TextView.GetBounds(source);
Rect characterBounds = textArea.TextView.GetCharacterBounds(textArea.Caret.Position, source);
CompositionForm form = new CompositionForm();
form.dwStyle = 0x0020;
form.ptCurrentPos.x = (int)Math.Max(characterBounds.Left, textViewBounds.Left);
form.ptCurrentPos.y = (int)Math.Max(characterBounds.Top, textViewBounds.Top);
form.rcArea.left = (int)textViewBounds.Left;
form.rcArea.top = (int)textViewBounds.Top;
form.rcArea.right = (int)textViewBounds.Right;
form.rcArea.bottom = (int)textViewBounds.Bottom;
return ImmSetCompositionWindow(hIMC, ref form);
}
public static bool SetCompositionFont(HwndSource source, IntPtr hIMC, TextArea textArea)
{
if (textArea == null)
throw new ArgumentNullException("textArea");
LOGFONT lf = new LOGFONT();
Rect characterBounds = textArea.TextView.GetCharacterBounds(textArea.Caret.Position, source);
lf.lfFaceName = textArea.FontFamily.Source;
lf.lfHeight = (int)characterBounds.Height;
return ImmSetCompositionFont(hIMC, ref lf);
}
static Rect GetBounds(this TextView textView, HwndSource source)
{
// this may happen during layout changes in AvalonDock, so we just return an empty rectangle
// in those cases. It should be refreshed immediately.
if (source.RootVisual == null || !source.RootVisual.IsAncestorOf(textView))
return EMPTY_RECT;
Rect displayRect = new Rect(0, 0, textView.ActualWidth, textView.ActualHeight);
return textView
.TransformToAncestor(source.RootVisual).TransformBounds(displayRect) // rect on root visual
.TransformToDevice(source.RootVisual); // rect on HWND
}
static readonly Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
static Rect GetCharacterBounds(this TextView textView, TextViewPosition pos, HwndSource source)
{
VisualLine vl = textView.GetVisualLine(pos.Line);
if (vl == null)
return EMPTY_RECT;
// this may happen during layout changes in AvalonDock, so we just return an empty rectangle
// in those cases. It should be refreshed immediately.
if (source.RootVisual == null || !source.RootVisual.IsAncestorOf(textView))
return EMPTY_RECT;
TextLine line = vl.GetTextLine(pos.VisualColumn, pos.IsAtEndOfLine);
Rect displayRect;
// calculate the display rect for the current character
if (pos.VisualColumn < vl.VisualLengthWithEndOfLineMarker) {
displayRect = line.GetTextBounds(pos.VisualColumn, 1).First().Rectangle;
displayRect.Offset(0, vl.GetTextLineVisualYPosition(line, VisualYPosition.LineTop));
} else {
// if we are in virtual space, we just use one wide-space as character width
displayRect = new Rect(vl.GetVisualPosition(pos.VisualColumn, VisualYPosition.TextTop),
new Size(textView.WideSpaceWidth, textView.DefaultLineHeight));
}
// adjust to current scrolling
displayRect.Offset(-textView.ScrollOffset);
return textView
.TransformToAncestor(source.RootVisual).TransformBounds(displayRect) // rect on root visual
.TransformToDevice(source.RootVisual); // rect on HWND
}
}
[ComImport, Guid("aa80e801-2021-11d2-93e0-0060b067b86e"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ITfThreadMgr
{
void Activate(out int clientId);
void Deactivate();
void CreateDocumentMgr(out IntPtr docMgr);
void EnumDocumentMgrs(out IntPtr enumDocMgrs);
void GetFocus(out IntPtr docMgr);
void SetFocus(IntPtr docMgr);
void AssociateFocus(IntPtr hwnd, IntPtr newDocMgr, out IntPtr prevDocMgr);
void IsThreadFocus([MarshalAs(UnmanagedType.Bool)] out bool isFocus);
void GetFunctionProvider(ref Guid classId, out IntPtr funcProvider);
void EnumFunctionProviders(out IntPtr enumProviders);
void GetGlobalCompartment(out IntPtr compartmentMgr);
}
}

165
AvalonEdit/ICSharpCode.AvalonEdit/Editing/ImeSupport.cs

@ -0,0 +1,165 @@ @@ -0,0 +1,165 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
namespace ICSharpCode.AvalonEdit.Editing
{
class ImeSupport
{
readonly TextArea textArea;
IntPtr currentContext;
IntPtr previousContext;
IntPtr defaultImeWnd;
HwndSource hwndSource;
EventHandler requerySuggestedHandler; // we need to keep the event handler instance alive because CommandManager.RequerySuggested uses weak references
bool isReadOnly;
public ImeSupport(TextArea textArea)
{
if (textArea == null)
throw new ArgumentNullException("textArea");
this.textArea = textArea;
InputMethod.SetIsInputMethodSuspended(this.textArea, textArea.Options.EnableImeSupport);
// We listen to CommandManager.RequerySuggested for both caret offset changes and changes to the set of read-only sections.
// This is because there's no dedicated event for read-only section changes; but RequerySuggested needs to be raised anyways
// to invalidate the Paste command.
requerySuggestedHandler = OnRequerySuggested;
CommandManager.RequerySuggested += requerySuggestedHandler;
textArea.OptionChanged += TextAreaOptionChanged;
}
void OnRequerySuggested(object sender, EventArgs e)
{
UpdateImeEnabled();
}
void TextAreaOptionChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "EnableImeSupport") {
InputMethod.SetIsInputMethodSuspended(this.textArea, textArea.Options.EnableImeSupport);
UpdateImeEnabled();
}
}
public void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
UpdateImeEnabled();
}
public void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
if (e.OldFocus == textArea && currentContext != IntPtr.Zero)
ImeNativeWrapper.NotifyIme(currentContext);
ClearContext();
}
void UpdateImeEnabled()
{
if (textArea.Options.EnableImeSupport && textArea.IsKeyboardFocused) {
bool newReadOnly = !textArea.ReadOnlySectionProvider.CanInsert(textArea.Caret.Offset);
if (hwndSource == null || isReadOnly != newReadOnly) {
ClearContext(); // clear existing context (on read-only change)
isReadOnly = newReadOnly;
CreateContext();
}
} else {
ClearContext();
}
}
void ClearContext()
{
if (hwndSource != null) {
ImeNativeWrapper.ImmAssociateContext(hwndSource.Handle, previousContext);
ImeNativeWrapper.ImmReleaseContext(defaultImeWnd, currentContext);
currentContext = IntPtr.Zero;
defaultImeWnd = IntPtr.Zero;
hwndSource.RemoveHook(WndProc);
hwndSource = null;
}
}
void CreateContext()
{
hwndSource = (HwndSource)PresentationSource.FromVisual(this.textArea);
if (hwndSource != null) {
if (isReadOnly) {
defaultImeWnd = IntPtr.Zero;
currentContext = IntPtr.Zero;
} else {
defaultImeWnd = ImeNativeWrapper.ImmGetDefaultIMEWnd(IntPtr.Zero);
currentContext = ImeNativeWrapper.ImmGetContext(defaultImeWnd);
}
previousContext = ImeNativeWrapper.ImmAssociateContext(hwndSource.Handle, currentContext);
hwndSource.AddHook(WndProc);
// UpdateCompositionWindow() will be called by the caret becoming visible
var threadMgr = ImeNativeWrapper.GetTextFrameworkThreadManager();
if (threadMgr != null) {
// Even though the docu says passing null is invalid, this seems to help
// activating the IME on the default input context that is shared with WPF
threadMgr.SetFocus(IntPtr.Zero);
}
}
}
IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg) {
case ImeNativeWrapper.WM_INPUTLANGCHANGE:
// Don't mark the message as handled; other windows
// might want to handle it as well.
// If we have a context, recreate it
if (hwndSource != null) {
ClearContext();
CreateContext();
}
break;
case ImeNativeWrapper.WM_IME_COMPOSITION:
UpdateCompositionWindow();
break;
}
return IntPtr.Zero;
}
public void UpdateCompositionWindow()
{
if (currentContext != IntPtr.Zero) {
ImeNativeWrapper.SetCompositionFont(hwndSource, currentContext, textArea);
ImeNativeWrapper.SetCompositionWindow(hwndSource, currentContext, textArea);
}
}
}
}

42
AvalonEdit/ICSharpCode.AvalonEdit/Editing/LineNumberMargin.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.ComponentModel;
@ -29,8 +44,17 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -29,8 +44,17 @@ namespace ICSharpCode.AvalonEdit.Editing
TextArea textArea;
Typeface typeface;
double emSize;
/// <summary>
/// The typeface used for rendering the line number margin.
/// This field is calculated in MeasureOverride() based on the FontFamily etc. properties.
/// </summary>
protected Typeface typeface;
/// <summary>
/// The font size used for rendering the line number margin.
/// This field is calculated in MeasureOverride() based on the FontFamily etc. properties.
/// </summary>
protected double emSize;
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
@ -79,7 +103,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -79,7 +103,7 @@ namespace ICSharpCode.AvalonEdit.Editing
newTextView.VisualLinesChanged += TextViewVisualLinesChanged;
// find the text area belonging to the new text view
textArea = newTextView.Services.GetService(typeof(TextArea)) as TextArea;
textArea = newTextView.GetService(typeof(TextArea)) as TextArea;
} else {
textArea = null;
}
@ -114,7 +138,10 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -114,7 +138,10 @@ namespace ICSharpCode.AvalonEdit.Editing
return ReceiveWeakEvent(managerType, sender, e);
}
int maxLineNumberLength = 1;
/// <summary>
/// Maximum length of a line number, in characters
/// </summary>
protected int maxLineNumberLength = 1;
void OnDocumentLineCountChanged()
{
@ -164,6 +191,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -164,6 +191,7 @@ namespace ICSharpCode.AvalonEdit.Editing
if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift) {
ExtendSelection(currentSeg);
}
textArea.Caret.BringCaretToView(5.0);
}
}
}
@ -172,6 +200,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -172,6 +200,7 @@ namespace ICSharpCode.AvalonEdit.Editing
{
Point pos = e.GetPosition(TextView);
pos.X = 0;
pos.Y = pos.Y.CoerceValue(0, TextView.ActualHeight);
pos.Y += TextView.VerticalOffset;
VisualLine vl = TextView.GetVisualLineFromVisualTop(pos.Y);
if (vl == null)
@ -207,6 +236,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -207,6 +236,7 @@ namespace ICSharpCode.AvalonEdit.Editing
if (currentSeg == SimpleSegment.Invalid)
return;
ExtendSelection(currentSeg);
textArea.Caret.BringCaretToView(5.0);
}
base.OnMouseMove(e);
}

26
AvalonEdit/ICSharpCode.AvalonEdit/Editing/NoReadOnlySections.cs

@ -1,10 +1,26 @@ @@ -1,10 +1,26 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Editing
@ -33,9 +49,9 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -33,9 +49,9 @@ namespace ICSharpCode.AvalonEdit.Editing
/// <summary>
/// <see cref="IReadOnlySectionProvider"/> that completely disables editing.
/// </summary>
sealed class ReadOnlyDocument : IReadOnlySectionProvider
sealed class ReadOnlySectionDocument : IReadOnlySectionProvider
{
public static readonly ReadOnlyDocument Instance = new ReadOnlyDocument();
public static readonly ReadOnlySectionDocument Instance = new ReadOnlySectionDocument();
public bool CanInsert(int offset)
{

182
AvalonEdit/ICSharpCode.AvalonEdit/Editing/RectangleSelection.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
@ -7,11 +22,16 @@ using System.IO; @@ -7,11 +22,16 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media.TextFormatting;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{
@ -20,20 +40,70 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -20,20 +40,70 @@ namespace ICSharpCode.AvalonEdit.Editing
/// </summary>
public sealed class RectangleSelection : Selection
{
#region Commands
/// <summary>
/// Expands the selection left by one character, creating a rectangular selection.
/// Key gesture: Alt+Shift+Left
/// </summary>
public static readonly RoutedUICommand BoxSelectLeftByCharacter = Command("BoxSelectLeftByCharacter");
/// <summary>
/// Expands the selection right by one character, creating a rectangular selection.
/// Key gesture: Alt+Shift+Right
/// </summary>
public static readonly RoutedUICommand BoxSelectRightByCharacter = Command("BoxSelectRightByCharacter");
/// <summary>
/// Expands the selection left by one word, creating a rectangular selection.
/// Key gesture: Ctrl+Alt+Shift+Left
/// </summary>
public static readonly RoutedUICommand BoxSelectLeftByWord = Command("BoxSelectLeftByWord");
/// <summary>
/// Expands the selection left by one word, creating a rectangular selection.
/// Key gesture: Ctrl+Alt+Shift+Right
/// </summary>
public static readonly RoutedUICommand BoxSelectRightByWord = Command("BoxSelectRightByWord");
/// <summary>
/// Expands the selection up by one line, creating a rectangular selection.
/// Key gesture: Alt+Shift+Up
/// </summary>
public static readonly RoutedUICommand BoxSelectUpByLine = Command("BoxSelectUpByLine");
/// <summary>
/// Expands the selection up by one line, creating a rectangular selection.
/// Key gesture: Alt+Shift+Down
/// </summary>
public static readonly RoutedUICommand BoxSelectDownByLine = Command("BoxSelectDownByLine");
/// <summary>
/// Expands the selection to the start of the line, creating a rectangular selection.
/// Key gesture: Alt+Shift+Home
/// </summary>
public static readonly RoutedUICommand BoxSelectToLineStart = Command("BoxSelectToLineStart");
/// <summary>
/// Expands the selection to the end of the line, creating a rectangular selection.
/// Key gesture: Alt+Shift+End
/// </summary>
public static readonly RoutedUICommand BoxSelectToLineEnd = Command("BoxSelectToLineEnd");
static RoutedUICommand Command(string name)
{
return new RoutedUICommand(name, name, typeof(RectangleSelection));
}
#endregion
TextDocument document;
readonly int startLine, endLine;
readonly double startXPos, endXPos;
readonly int topLeftOffset, bottomRightOffset;
readonly TextViewPosition start, end;
readonly List<SelectionSegment> segments = new List<SelectionSegment>();
void InitDocument()
{
document = textArea.Document;
if (document == null)
throw ThrowUtil.NoDocumentAssigned();
}
#region Constructors
/// <summary>
/// Creates a new rectangular selection.
/// </summary>
@ -48,6 +118,9 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -48,6 +118,9 @@ namespace ICSharpCode.AvalonEdit.Editing
CalculateSegments();
this.topLeftOffset = this.segments.First().StartOffset;
this.bottomRightOffset = this.segments.Last().EndOffset;
this.start = start;
this.end = end;
}
private RectangleSelection(TextArea textArea, int startLine, double startXPos, TextViewPosition end)
@ -61,6 +134,9 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -61,6 +134,9 @@ namespace ICSharpCode.AvalonEdit.Editing
CalculateSegments();
this.topLeftOffset = this.segments.First().StartOffset;
this.bottomRightOffset = this.segments.Last().EndOffset;
this.start = GetStart();
this.end = end;
}
private RectangleSelection(TextArea textArea, TextViewPosition start, int endLine, double endXPos)
@ -74,6 +150,16 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -74,6 +150,16 @@ namespace ICSharpCode.AvalonEdit.Editing
CalculateSegments();
this.topLeftOffset = this.segments.First().StartOffset;
this.bottomRightOffset = this.segments.Last().EndOffset;
this.start = start;
this.end = GetEnd();
}
void InitDocument()
{
document = textArea.Document;
if (document == null)
throw ThrowUtil.NoDocumentAssigned();
}
static double GetXPos(TextArea textArea, TextViewPosition pos)
@ -81,16 +167,48 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -81,16 +167,48 @@ namespace ICSharpCode.AvalonEdit.Editing
DocumentLine documentLine = textArea.Document.GetLineByNumber(pos.Line);
VisualLine visualLine = textArea.TextView.GetOrConstructVisualLine(documentLine);
int vc = visualLine.ValidateVisualColumn(pos, true);
TextLine textLine = visualLine.GetTextLine(vc);
TextLine textLine = visualLine.GetTextLine(vc, pos.IsAtEndOfLine);
return visualLine.GetTextLineVisualXPosition(textLine, vc);
}
int GetVisualColumnFromXPos(int line, double xPos)
void CalculateSegments()
{
var vl = textArea.TextView.GetOrConstructVisualLine(textArea.Document.GetLineByNumber(line));
return vl.GetVisualColumn(new Point(xPos, 0), true);
DocumentLine nextLine = document.GetLineByNumber(Math.Min(startLine, endLine));
do {
VisualLine vl = textArea.TextView.GetOrConstructVisualLine(nextLine);
int startVC = vl.GetVisualColumn(new Point(startXPos, 0), true);
int endVC = vl.GetVisualColumn(new Point(endXPos, 0), true);
int baseOffset = vl.FirstDocumentLine.Offset;
int startOffset = baseOffset + vl.GetRelativeOffset(startVC);
int endOffset = baseOffset + vl.GetRelativeOffset(endVC);
segments.Add(new SelectionSegment(startOffset, startVC, endOffset, endVC));
nextLine = vl.LastDocumentLine.NextLine;
} while (nextLine != null && nextLine.LineNumber <= Math.Max(startLine, endLine));
}
TextViewPosition GetStart()
{
SelectionSegment segment = (startLine < endLine ? segments.First() : segments.Last());
if (startXPos < endXPos) {
return new TextViewPosition(document.GetLocation(segment.StartOffset), segment.StartVisualColumn);
} else {
return new TextViewPosition(document.GetLocation(segment.EndOffset), segment.EndVisualColumn);
}
}
TextViewPosition GetEnd()
{
SelectionSegment segment = (startLine < endLine ? segments.Last() : segments.First());
if (startXPos < endXPos) {
return new TextViewPosition(document.GetLocation(segment.EndOffset), segment.EndVisualColumn);
} else {
return new TextViewPosition(document.GetLocation(segment.StartOffset), segment.StartVisualColumn);
}
}
#endregion
/// <inheritdoc/>
public override string GetText()
{
@ -133,22 +251,14 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -133,22 +251,14 @@ namespace ICSharpCode.AvalonEdit.Editing
get { return segments; }
}
/// <inheritdoc/>
public override TextViewPosition StartPosition {
get { return start; }
}
void CalculateSegments()
{
DocumentLine nextLine = document.GetLineByNumber(Math.Min(startLine, endLine));
do {
VisualLine vl = textArea.TextView.GetOrConstructVisualLine(nextLine);
int startVC = vl.GetVisualColumn(new Point(startXPos, 0), true);
int endVC = vl.GetVisualColumn(new Point(endXPos, 0), true);
int baseOffset = vl.FirstDocumentLine.Offset;
int startOffset = baseOffset + vl.GetRelativeOffset(startVC);
int endOffset = baseOffset + vl.GetRelativeOffset(endVC);
segments.Add(new SelectionSegment(startOffset, startVC, endOffset, endVC));
nextLine = vl.LastDocumentLine.NextLine;
} while (nextLine != null && nextLine.LineNumber <= Math.Max(startLine, endLine));
/// <inheritdoc/>
public override TextViewPosition EndPosition {
get { return end; }
}
/// <inheritdoc/>
@ -173,6 +283,12 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -173,6 +283,12 @@ namespace ICSharpCode.AvalonEdit.Editing
return new RectangleSelection(textArea, startLine, startXPos, endPosition);
}
int GetVisualColumnFromXPos(int line, double xPos)
{
var vl = textArea.TextView.GetOrConstructVisualLine(textArea.Document.GetLineByNumber(line));
return vl.GetVisualColumn(new Point(xPos, 0), true);
}
/// <inheritdoc/>
public override Selection UpdateOnDocumentChange(DocumentChangeEventArgs e)
{
@ -282,9 +398,11 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -282,9 +398,11 @@ namespace ICSharpCode.AvalonEdit.Editing
{
var data = base.CreateDataObject(textArea);
MemoryStream isRectangle = new MemoryStream(1);
isRectangle.WriteByte(1);
data.SetData(RectangularSelectionDataType, isRectangle, false);
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, RectangularSelectionDataType)) {
MemoryStream isRectangle = new MemoryStream(1);
isRectangle.WriteByte(1);
data.SetData(RectangularSelectionDataType, isRectangle, false);
}
return data;
}

64
AvalonEdit/ICSharpCode.AvalonEdit/Editing/Selection.cs

@ -1,13 +1,32 @@ @@ -1,13 +1,32 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{
@ -63,6 +82,16 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -63,6 +82,16 @@ namespace ICSharpCode.AvalonEdit.Editing
this.textArea = textArea;
}
/// <summary>
/// Gets the start position of the selection.
/// </summary>
public abstract TextViewPosition StartPosition { get; }
/// <summary>
/// Gets the end position of the selection.
/// </summary>
public abstract TextViewPosition EndPosition { get; }
/// <summary>
/// Gets the selected text segments.
/// </summary>
@ -104,7 +133,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -104,7 +133,7 @@ namespace ICSharpCode.AvalonEdit.Editing
{
return (!string.IsNullOrEmpty(newText) || !(IsInVirtualSpace(start) && IsInVirtualSpace(end)))
&& newText != "\r\n"
&& newText != "\n"
&& newText != "\n"
&& newText != "\r";
}
@ -228,9 +257,9 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -228,9 +257,9 @@ namespace ICSharpCode.AvalonEdit.Editing
{
if (this.IsEmpty)
return false;
if (this.SurroundingSegment.Contains(offset)) {
if (this.SurroundingSegment.Contains(offset, 0)) {
foreach (ISegment s in this.Segments) {
if (s.Contains(offset)) {
if (s.Contains(offset, 0)) {
return true;
}
}
@ -243,15 +272,30 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -243,15 +272,30 @@ namespace ICSharpCode.AvalonEdit.Editing
/// </summary>
public virtual DataObject CreateDataObject(TextArea textArea)
{
string text = GetText();
DataObject data = new DataObject();
// Ensure we use the appropriate newline sequence for the OS
DataObject data = new DataObject(TextUtilities.NormalizeNewLines(text, Environment.NewLine));
// we cannot use DataObject.SetText - then we cannot drag to SciTe
// (but dragging to Word works in both cases)
string text = TextUtilities.NormalizeNewLines(GetText(), Environment.NewLine);
// Enable drag/drop to Word, Notepad++ and others
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, DataFormats.UnicodeText)) {
data.SetText(text);
}
// Enable drag/drop to SciTe:
// We cannot use SetText, thus we need to use typeof(string).FullName as data format.
// new DataObject(object) calls SetData(object), which in turn calls SetData(Type, data),
// which then uses Type.FullName as format.
// We immitate that behavior here as well:
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, typeof(string).FullName)) {
data.SetData(typeof(string).FullName, text);
}
// Also copy text in HTML format to clipboard - good for pasting text into Word
// or to the SharpDevelop forums.
HtmlClipboard.SetHtml(data, CreateHtmlFragment(new HtmlOptions(textArea.Options)));
if (EditingCommandHandler.ConfirmDataFormat(textArea, data, DataFormats.Html)) {
HtmlClipboard.SetHtml(data, CreateHtmlFragment(new HtmlOptions(textArea.Options)));
}
return data;
}
}

24
AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionColorizer.cs

@ -1,10 +1,26 @@ @@ -1,10 +1,26 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{

19
AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionLayer.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows;

77
AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionMouseHandler.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.ComponentModel;
@ -14,6 +29,9 @@ using System.Windows.Threading; @@ -14,6 +29,9 @@ using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{
@ -166,9 +184,10 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -166,9 +184,10 @@ namespace ICSharpCode.AvalonEdit.Editing
if (e.Data.GetDataPresent(DataFormats.UnicodeText, true)) {
e.Handled = true;
int visualColumn;
int offset = GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn);
bool isAtEndOfLine;
int offset = GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn, out isAtEndOfLine);
if (offset >= 0) {
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn);
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn) { IsAtEndOfLine = isAtEndOfLine };
textArea.Caret.DesiredXPos = double.NaN;
if (textArea.ReadOnlySectionProvider.CanInsert(offset)) {
if ((e.AllowedEffects & DragDropEffects.Move) == DragDropEffects.Move
@ -217,6 +236,21 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -217,6 +236,21 @@ namespace ICSharpCode.AvalonEdit.Editing
string newLine = TextUtilities.GetNewLineFromDocument(textArea.Document, textArea.Caret.Line);
text = TextUtilities.NormalizeNewLines(text, newLine);
string pasteFormat;
// fill the suggested DataFormat used for the paste action:
if (rectangular)
pasteFormat = RectangleSelection.RectangularSelectionDataType;
else
pasteFormat = DataFormats.UnicodeText;
var pastingEventArgs = new DataObjectPastingEventArgs(e.Data, true, pasteFormat);
textArea.RaiseEvent(pastingEventArgs);
if (pastingEventArgs.CommandCancelled)
return;
// DataObject.PastingEvent handlers might have changed the format to apply.
rectangular = pastingEventArgs.FormatToApply == RectangleSelection.RectangularSelectionDataType;
// Mark the undo group with the currentDragDescriptor, if the drag
// is originating from the same control. This allows combining
// the undo groups when text is moved.
@ -246,7 +280,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -246,7 +280,7 @@ namespace ICSharpCode.AvalonEdit.Editing
// we re-throw them later to allow the application's unhandled exception handler
// to catch them
textArea.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
DispatcherPriority.Send,
new Action(delegate {
throw new DragDropException("Exception during drag'n'drop", ex);
}));
@ -303,6 +337,11 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -303,6 +337,11 @@ namespace ICSharpCode.AvalonEdit.Editing
}
}
var copyingEventArgs = new DataObjectCopyingEventArgs(dataObject, true);
textArea.RaiseEvent(copyingEventArgs);
if (copyingEventArgs.CommandCancelled)
return;
object dragDescriptor = new object();
this.currentDragDescriptor = dragDescriptor;
@ -359,7 +398,8 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -359,7 +398,8 @@ namespace ICSharpCode.AvalonEdit.Editing
Point p = e.GetPosition(textArea.TextView);
if (p.X >= 0 && p.Y >= 0 && p.X <= textArea.TextView.ActualWidth && p.Y <= textArea.TextView.ActualHeight) {
int visualColumn;
int offset = GetOffsetFromMousePosition(e, out visualColumn);
bool isAtEndOfLine;
int offset = GetOffsetFromMousePosition(e, out visualColumn, out isAtEndOfLine);
if (textArea.Selection.Contains(offset))
e.Cursor = Cursors.Arrow;
else
@ -380,7 +420,8 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -380,7 +420,8 @@ namespace ICSharpCode.AvalonEdit.Editing
bool shift = (modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
if (enableTextDragDrop && e.ClickCount == 1 && !shift) {
int visualColumn;
int offset = GetOffsetFromMousePosition(e, out visualColumn);
bool isAtEndOfLine;
int offset = GetOffsetFromMousePosition(e, out visualColumn, out isAtEndOfLine);
if (textArea.Selection.Contains(offset)) {
if (textArea.CaptureMouse()) {
mode = SelectionMode.PossibleDragStart;
@ -488,12 +529,12 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -488,12 +529,12 @@ namespace ICSharpCode.AvalonEdit.Editing
}
}
int GetOffsetFromMousePosition(MouseEventArgs e, out int visualColumn)
int GetOffsetFromMousePosition(MouseEventArgs e, out int visualColumn, out bool isAtEndOfLine)
{
return GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn);
return GetOffsetFromMousePosition(e.GetPosition(textArea.TextView), out visualColumn, out isAtEndOfLine);
}
int GetOffsetFromMousePosition(Point positionRelativeToTextView, out int visualColumn)
int GetOffsetFromMousePosition(Point positionRelativeToTextView, out int visualColumn, out bool isAtEndOfLine)
{
visualColumn = 0;
TextView textView = textArea.TextView;
@ -507,9 +548,10 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -507,9 +548,10 @@ namespace ICSharpCode.AvalonEdit.Editing
pos.Y = textView.DocumentHeight - ExtensionMethods.Epsilon;
VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y);
if (line != null) {
visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace);
visualColumn = line.GetVisualColumn(pos, textArea.Selection.EnableVirtualSpace, out isAtEndOfLine);
return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
}
isAtEndOfLine = false;
return -1;
}
@ -527,7 +569,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -527,7 +569,7 @@ namespace ICSharpCode.AvalonEdit.Editing
pos.Y = textView.DocumentHeight - ExtensionMethods.Epsilon;
VisualLine line = textView.GetVisualLineFromVisualTop(pos.Y);
if (line != null) {
visualColumn = line.GetVisualColumn(line.TextLines.First(), positionRelativeToTextView.X, textArea.Selection.EnableVirtualSpace);
visualColumn = line.GetVisualColumn(line.TextLines.First(), pos.X, textArea.Selection.EnableVirtualSpace);
return line.GetRelativeOffset(visualColumn) + line.FirstDocumentLine.Offset;
}
return -1;
@ -568,16 +610,19 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -568,16 +610,19 @@ namespace ICSharpCode.AvalonEdit.Editing
void SetCaretOffsetToMousePosition(MouseEventArgs e, ISegment allowedSegment)
{
int visualColumn;
bool isAtEndOfLine;
int offset;
if (mode == SelectionMode.Rectangular)
if (mode == SelectionMode.Rectangular) {
offset = GetOffsetFromMousePositionFirstTextLineOnly(e.GetPosition(textArea.TextView), out visualColumn);
else
offset = GetOffsetFromMousePosition(e, out visualColumn);
isAtEndOfLine = true;
} else {
offset = GetOffsetFromMousePosition(e, out visualColumn, out isAtEndOfLine);
}
if (allowedSegment != null) {
offset = offset.CoerceValue(allowedSegment.Offset, allowedSegment.EndOffset);
}
if (offset >= 0) {
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn);
textArea.Caret.Position = new TextViewPosition(textArea.Document.GetLocation(offset), visualColumn) { IsAtEndOfLine = isAtEndOfLine };
textArea.Caret.DesiredXPos = double.NaN;
}
}

23
AvalonEdit/ICSharpCode.AvalonEdit/Editing/SelectionSegment.cs

@ -1,8 +1,27 @@ @@ -1,8 +1,27 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#else
using ICSharpCode.AvalonEdit.Document;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{

66
AvalonEdit/ICSharpCode.AvalonEdit/Editing/SimpleSelection.cs

@ -1,12 +1,28 @@ @@ -1,12 +1,28 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Utils;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{
@ -56,10 +72,16 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -56,10 +72,16 @@ namespace ICSharpCode.AvalonEdit.Editing
if (segmentsToDelete[i].Offset == SurroundingSegment.Offset && segmentsToDelete[i].Length == SurroundingSegment.Length) {
newText = AddSpacesIfRequired(newText, start, end);
}
int vc = textArea.Caret.VisualColumn;
textArea.Caret.Offset = segmentsToDelete[i].EndOffset;
if (string.IsNullOrEmpty(newText))
textArea.Caret.VisualColumn = vc;
if (string.IsNullOrEmpty(newText)) {
// place caret at the beginning of the selection
if (start.CompareTo(end) <= 0)
textArea.Caret.Position = start;
else
textArea.Caret.Position = end;
} else {
// place caret so that it ends up behind the new text
textArea.Caret.Offset = segmentsToDelete[i].EndOffset;
}
textArea.Document.Replace(segmentsToDelete[i], newText);
} else {
textArea.Document.Remove(segmentsToDelete[i]);
@ -71,18 +93,12 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -71,18 +93,12 @@ namespace ICSharpCode.AvalonEdit.Editing
}
}
/// <summary>
/// Gets the start offset.
/// </summary>
public int StartOffset {
get { return startOffset; }
public override TextViewPosition StartPosition {
get { return start; }
}
/// <summary>
/// Gets the end offset.
/// </summary>
public int EndOffset {
get { return endOffset; }
public override TextViewPosition EndPosition {
get { return end; }
}
/// <inheritdoc/>
@ -90,16 +106,24 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -90,16 +106,24 @@ namespace ICSharpCode.AvalonEdit.Editing
{
if (e == null)
throw new ArgumentNullException("e");
int newStartOffset, newEndOffset;
if (startOffset <= endOffset) {
newStartOffset = e.GetNewOffset(startOffset, AnchorMovementType.Default);
newEndOffset = Math.Max(newStartOffset, e.GetNewOffset(endOffset, AnchorMovementType.BeforeInsertion));
} else {
newEndOffset = e.GetNewOffset(endOffset, AnchorMovementType.Default);
newStartOffset = Math.Max(newEndOffset, e.GetNewOffset(startOffset, AnchorMovementType.BeforeInsertion));
}
return Selection.Create(
textArea,
new TextViewPosition(textArea.Document.GetLocation(e.GetNewOffset(startOffset, AnchorMovementType.Default)), start.VisualColumn),
new TextViewPosition(textArea.Document.GetLocation(e.GetNewOffset(endOffset, AnchorMovementType.Default)), end.VisualColumn)
new TextViewPosition(textArea.Document.GetLocation(newStartOffset), start.VisualColumn),
new TextViewPosition(textArea.Document.GetLocation(newEndOffset), end.VisualColumn)
);
}
/// <inheritdoc/>
public override bool IsEmpty {
get { return startOffset == endOffset; }
get { return startOffset == endOffset && start.VisualColumn == end.VisualColumn; }
}
/// <inheritdoc/>

117
AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextArea.cs

@ -1,8 +1,22 @@ @@ -1,8 +1,22 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
@ -11,16 +25,16 @@ using System.Linq; @@ -11,16 +25,16 @@ using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Indentation;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Editor;
namespace ICSharpCode.AvalonEdit.Editing
{
@ -29,6 +43,8 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -29,6 +43,8 @@ namespace ICSharpCode.AvalonEdit.Editing
/// </summary>
public class TextArea : Control, IScrollInfo, IWeakEventListener, ITextEditorComponent, IServiceProvider
{
internal readonly ImeSupport ime;
#region Constructor
static TextArea()
{
@ -68,6 +84,9 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -68,6 +84,9 @@ namespace ICSharpCode.AvalonEdit.Editing
caret = new Caret(this);
caret.PositionChanged += (sender, e) => RequestSelectionValidation();
caret.PositionChanged += CaretPositionChanged;
AttachTypingEvents();
ime = new ImeSupport(this);
leftMargins.CollectionChanged += leftMargins_CollectionChanged;
@ -557,6 +576,14 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -557,6 +576,14 @@ namespace ICSharpCode.AvalonEdit.Editing
get { return caret; }
}
void CaretPositionChanged(object sender, EventArgs e)
{
if (textView == null)
return;
this.textView.HighlightedLine = this.Caret.Line;
}
ObservableCollection<UIElement> leftMargins = new ObservableCollection<UIElement>();
/// <summary>
@ -593,6 +620,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -593,6 +620,7 @@ namespace ICSharpCode.AvalonEdit.Editing
if (value == null)
throw new ArgumentNullException("value");
readOnlySectionProvider = value;
CommandManager.InvalidateRequerySuggested(); // the read-only status effects Paste.CanExecute and the IME
}
}
#endregion
@ -754,6 +782,8 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -754,6 +782,8 @@ namespace ICSharpCode.AvalonEdit.Editing
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
// First activate IME, then show caret
ime.OnGotKeyboardFocus(e);
caret.Show();
}
@ -762,6 +792,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -762,6 +792,7 @@ namespace ICSharpCode.AvalonEdit.Editing
{
base.OnLostKeyboardFocus(e);
caret.Hide();
ime.OnLostKeyboardFocus(e);
}
#endregion
@ -817,6 +848,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -817,6 +848,7 @@ namespace ICSharpCode.AvalonEdit.Editing
// We have to ignore those (not handle them) to keep the shortcut working.
return;
}
HideMouseCursor();
PerformTextInput(e);
e.Handled = true;
}
@ -850,8 +882,11 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -850,8 +882,11 @@ namespace ICSharpCode.AvalonEdit.Editing
if (!e.Handled) {
if (e.Text == "\n" || e.Text == "\r" || e.Text == "\r\n")
ReplaceSelectionWithNewLine();
else
else {
if (OverstrikeMode && Selection.IsEmpty && Document.GetLineByNumber(Caret.Line).EndOffset > Caret.Offset)
EditingCommands.SelectRightByCharacter.Execute(null, this);
ReplaceSelectionWithText(e.Text);
}
OnTextEntered(e);
caret.BringCaretToView();
}
@ -936,6 +971,13 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -936,6 +971,13 @@ namespace ICSharpCode.AvalonEdit.Editing
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if (!e.Handled && e.Key == Key.Insert && this.Options.AllowToggleOverstrikeMode) {
this.OverstrikeMode = !this.OverstrikeMode;
e.Handled = true;
return;
}
foreach (TextAreaStackedInputHandler h in stackedInputHandlers) {
if (e.Handled)
break;
@ -959,15 +1001,68 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -959,15 +1001,68 @@ namespace ICSharpCode.AvalonEdit.Editing
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
TextView.InvalidateCursor();
TextView.InvalidateCursorIfMouseWithinTextView();
}
/// <inheritdoc/>
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
TextView.InvalidateCursor();
TextView.InvalidateCursorIfMouseWithinTextView();
}
#endregion
#region Hide Mouse Cursor While Typing
bool isMouseCursorHidden;
void AttachTypingEvents()
{
// Use the PreviewMouseMove event in case some other editor layer consumes the MouseMove event (e.g. SD's InsertionCursorLayer)
this.MouseEnter += delegate { ShowMouseCursor(); };
this.MouseLeave += delegate { ShowMouseCursor(); };
this.PreviewMouseMove += delegate { ShowMouseCursor(); };
#if DOTNET4
this.TouchEnter += delegate { ShowMouseCursor(); };
this.TouchLeave += delegate { ShowMouseCursor(); };
this.PreviewTouchMove += delegate { ShowMouseCursor(); };
#endif
}
void ShowMouseCursor()
{
if (this.isMouseCursorHidden) {
System.Windows.Forms.Cursor.Show();
this.isMouseCursorHidden = false;
}
}
void HideMouseCursor() {
if (Options.HideCursorWhileTyping && !this.isMouseCursorHidden && this.IsMouseOver) {
this.isMouseCursorHidden = true;
System.Windows.Forms.Cursor.Hide();
}
}
#endregion
#region Overstrike mode
/// <summary>
/// The <see cref="OverstrikeMode"/> dependency property.
/// </summary>
public static readonly DependencyProperty OverstrikeModeProperty =
DependencyProperty.Register("OverstrikeMode", typeof(bool), typeof(TextArea),
new FrameworkPropertyMetadata(Boxes.False));
/// <summary>
/// Gets/Sets whether overstrike mode is active.
/// </summary>
public bool OverstrikeMode {
get { return (bool)GetValue(OverstrikeModeProperty); }
set { SetValue(OverstrikeModeProperty, value); }
}
#endregion
/// <inheritdoc/>
@ -987,6 +1082,8 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -987,6 +1082,8 @@ namespace ICSharpCode.AvalonEdit.Editing
|| e.Property == SelectionCornerRadiusProperty)
{
textView.Redraw();
} else if (e.Property == OverstrikeModeProperty) {
caret.UpdateIfVisible();
}
}
@ -996,7 +1093,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -996,7 +1093,7 @@ namespace ICSharpCode.AvalonEdit.Editing
/// <returns>Returns the requested service instance, or null if the service cannot be found.</returns>
public virtual object GetService(Type serviceType)
{
return textView.Services.GetService(serviceType);
return textView.GetService(serviceType);
}
/// <summary>

21
AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
@ -59,7 +74,7 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -59,7 +74,7 @@ namespace ICSharpCode.AvalonEdit.Editing
// Work around WPF memory leak:
// KeyBinding retains a reference to whichever UIElement it is used in first.
// Using a dummy element for this purpose ensures that we don't leak
// a real text editor (which a potentially large document).
// a real text editor (with a potentially large document).
UIElement dummyElement = new UIElement();
dummyElement.InputBindings.AddRange(inputBindings);
}

19
AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.AvalonEdit.Utils;
using System;

27
AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextSegmentReadOnlySectionProvider.cs

@ -1,9 +1,27 @@ @@ -1,9 +1,27 @@
// 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)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using ICSharpCode.AvalonEdit.Document;
#if NREFACTORY
using ICSharpCode.NRefactory.Editor;
#endif
namespace ICSharpCode.AvalonEdit.Editing
{
@ -60,6 +78,11 @@ namespace ICSharpCode.AvalonEdit.Editing @@ -60,6 +78,11 @@ namespace ICSharpCode.AvalonEdit.Editing
if (segment == null)
throw new ArgumentNullException("segment");
if (segment.Length == 0 && CanInsert(segment.Offset)) {
yield return segment;
yield break;
}
int readonlyUntil = segment.Offset;
foreach (TextSegment ts in segments.FindOverlappingSegments(segment)) {
int start = ts.StartOffset;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save