Browse Source

Added support for advanced syntax highlighters.

Boo: Assignments that introduce new local variables are highlighted.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@1392 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 20 years ago
parent
commit
a3b4fd0301
  1. 4
      src/AddIns/BackendBindings/Boo/BooBinding.sln
  2. 4
      src/AddIns/BackendBindings/Boo/BooBinding/Project/BooBinding.addin
  3. 4
      src/AddIns/BackendBindings/Boo/BooBinding/Project/BooBinding.csproj
  4. 6
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/BooLanguageProperties.cs
  5. 155
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooAdvancedHighlighter.cs
  6. 2
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooParser.cs
  7. 23
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooRefactoringProvider.cs
  8. 1
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs
  9. 2
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/VariableLookupVisitor.cs
  10. 3
      src/AddIns/Misc/CodeAnalysis/CodeAnalysis.addin
  11. 18
      src/AddIns/Misc/HighlightingEditor/Project/Src/Nodes/EnvironmentNode.cs
  12. 1
      src/Libraries/ICSharpCode.TextEditor/Project/Resources/Boo.xshd
  13. 101
      src/Libraries/ICSharpCode.TextEditor/Project/Resources/Mode.xsd
  14. 40
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs
  15. 24
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/HighlightingDefinitionParser.cs
  16. 9
      src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControlBase.cs
  17. 3
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  18. 10
      src/Main/Base/Project/Src/Services/ParserService/ParseInformationEventHandler.cs
  19. 2
      src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
  20. 11
      src/Main/Base/Project/Src/Services/RefactoringService/NRefactoryRefactoringProvider.cs
  21. 15
      src/Main/Base/Project/Src/Services/RefactoringService/RefactorMenu.cs
  22. 14
      src/Main/Base/Project/Src/Services/RefactoringService/RefactoringProvider.cs
  23. 3
      src/Main/Base/Project/Src/TextEditor/Commands/TextAreaContextmenuCommands.cs
  24. 101
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/ParserHighlightingStrategy.cs
  25. 46
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs
  26. 3
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/TextEditorDisplayBinding.cs

4
src/AddIns/BackendBindings/Boo/BooBinding.sln

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# SharpDevelop 2.1.0.1333
# SharpDevelop 2.1.0.1388
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRefactoryToBooConverter", "NRefactoryToBooConverter\Project\NRefactoryToBooConverter.csproj", "{DBCF20A1-BA13-4582-BFA9-74DE4D987B73}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRefactoryToBooConverter.Tests", "NRefactoryToBooConverter\Test\NRefactoryToBooConverter.Tests.csproj", "{C9DE556D-325C-4544-B29F-16A9EB7C9830}"
@ -22,6 +22,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FormsDesigner", "..\..\Disp @@ -22,6 +22,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FormsDesigner", "..\..\Disp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BooBinding.Tests", "BooBinding\Test\BooBinding.Tests.csproj", "{6FA16499-896F-4C02-BB43-1AF5C6C7C713}"
EndProject
Project("{A33008B1-5DAC-44D5-9060-242E3B6E38F2}") = "Boo.InterpreterAddIn", "Boo.InterpreterAddIn\Project\Boo.InterpreterAddIn.booproj", "{928E34B2-5E46-4A4D-8E4D-2CA2CCDB905A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU

4
src/AddIns/BackendBindings/Boo/BooBinding/Project/BooBinding.addin

@ -88,6 +88,10 @@ @@ -88,6 +88,10 @@
<Class id = "BooFormatter" class = "Grunwald.BooBinding.BooFormattingStrategy"/>
</Path>
<Path name = "/AddIns/DefaultTextEditor/AdvancedHighlighter/Boo">
<Class id = "BooFormatter" class = "Grunwald.BooBinding.CodeCompletion.BooAdvancedHighlighter"/>
</Path>
<Path name = "/AddIns/DefaultTextEditor/CodeCompletion">
<CodeCompletionBinding id = "Boo" extensions = ".boo" class = "Grunwald.BooBinding.CodeCompletion.CompletionBinding"/>
</Path>

4
src/AddIns/BackendBindings/Boo/BooBinding/Project/BooBinding.csproj

@ -89,6 +89,8 @@ @@ -89,6 +89,8 @@
<None Include="Templates\DefaultAssemblyInfo.boo">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Compile Include="Src\CodeCompletion\BooRefactoringProvider.cs" />
<Compile Include="Src\CodeCompletion\BooAdvancedHighlighter.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="BooBinding.addin">
@ -150,4 +152,4 @@ @@ -150,4 +152,4 @@
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Import Project="PostBuildEvent.proj" />
</Project>
</Project>

6
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/BooLanguageProperties.cs

@ -45,5 +45,11 @@ namespace Grunwald.BooBinding @@ -45,5 +45,11 @@ namespace Grunwald.BooBinding
return true;
}
}
public override ICSharpCode.SharpDevelop.Refactoring.RefactoringProvider RefactoringProvider {
get {
return CodeCompletion.BooRefactoringProvider.BooProvider;
}
}
}
}

155
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooAdvancedHighlighter.cs

@ -0,0 +1,155 @@ @@ -0,0 +1,155 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using Boo.Lang.Compiler.Ast;
using ICSharpCode.Core;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
namespace Grunwald.BooBinding.CodeCompletion
{
public class BooAdvancedHighlighter : IAdvancedHighlighter
{
public event EventHandler MarkOutstandingRequests;
TextEditorControl textEditor;
volatile Dictionary<int, List<int>> declarations;
public void Initialize(TextEditorControl textEditor)
{
LoggingService.Debug("AdvancedHighlighter created");
this.textEditor = textEditor;
ParserService.ParserUpdateStepFinished += OnUpdateStep;
}
public void Dispose()
{
LoggingService.Debug("AdvancedHighlighter destroyed");
ParserService.ParserUpdateStepFinished -= OnUpdateStep;
}
private class FindAssignmentsVisitor : DepthFirstVisitor
{
public Dictionary<int, List<int>> declarations = new Dictionary<int, List<int>>();
// Possible declarations:
// Dictionary<LineNumber, List<ColumnNumber>>
// LineNumber and ColumnNumber are 0-based (text editor coordinates)
public override void OnBinaryExpression(BinaryExpression node)
{
ReferenceExpression reference = node.Left as ReferenceExpression;
if (node.Operator == BinaryOperatorType.Assign
&& reference != null
&& !(reference is MemberReferenceExpression)
&& reference.LexicalInfo.IsValid)
{
int lineNumber = reference.LexicalInfo.Line - 1;
List<int> l;
if (!declarations.TryGetValue(lineNumber, out l)) {
l = new List<int>();
declarations.Add(lineNumber, l);
}
l.Add(reference.LexicalInfo.Column - 1);
}
base.OnBinaryExpression(node);
}
protected override void OnError(Node node, Exception error)
{
MessageService.ShowError(error, "VariableLookupVisitor: error processing " + node);
}
}
void OnUpdateStep(object sender, ParserUpdateStepEventArgs e)
{
if (FileUtility.IsEqualFileName(e.FileName, textEditor.FileName)) {
ParseInformation parseInfo = e.ParseInformation;
if (parseInfo == null && this.declarations == null)
parseInfo = ParserService.GetParseInformation(textEditor.FileName);
if (parseInfo != null) {
ICompilationUnit cu = parseInfo.MostRecentCompilationUnit;
CompileUnit booCu = cu.Tag as CompileUnit;
if (booCu != null) {
FindAssignmentsVisitor visitor = new FindAssignmentsVisitor();
booCu.Accept(visitor);
this.declarations = visitor.declarations; // volatile access!
}
}
WorkbenchSingleton.SafeThreadAsyncCall(this, "RaiseMarkOutstandingRequests", e);
}
}
bool markingOutstanding;
int resolveCount;
void RaiseMarkOutstandingRequests(EventArgs e)
{
#if DEBUG
int time = Environment.TickCount;
#endif
markingOutstanding = true;
resolveCount = 0;
if (MarkOutstandingRequests != null) {
MarkOutstandingRequests(this, e);
}
markingOutstanding = false;
#if DEBUG
if (resolveCount > 0) {
LoggingService.Debug("AdvancedHighlighter took " + (Environment.TickCount - time) + " ms for " + resolveCount + " resolves");
}
#endif
textEditor.Document.CommitUpdate();
}
public void MarkLine(IDocument document, LineSegment currentLine, List<TextWord> words)
{
Dictionary<int, List<int>> decl = this.declarations; // volatile access!
if (decl == null) return;
int currentLineOffset = currentLine.Offset;
int lineNumber = document.GetLineNumberForOffset(currentLineOffset);
List<int> list;
bool changedLine = false;
if (decl.TryGetValue(lineNumber, out list)) {
foreach (TextWord word in words) {
if (word.Type == TextWordType.Word) {
for (int i = 0; i < list.Count; i++) {
if (word.Offset == list[i]) {
LocalResolveResult rr;
resolveCount++;
rr = ParserService.Resolve(new ExpressionResult(word.Word),
lineNumber + 1, word.Offset + 1,
textEditor.FileName,
textEditor.Document.TextContent
) as LocalResolveResult;
if (rr != null
&& rr.Field.Region.BeginLine == lineNumber + 1
&& rr.Field.Region.BeginColumn == word.Offset + 1)
{
changedLine = true;
word.SyntaxColor = textEditor.Document.HighlightingStrategy.GetColorFor("LocalVariableCreation");
} else {
list.RemoveAt(i--);
}
}
}
}
}
}
if (markingOutstanding && changedLine) {
textEditor.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.SingleLine, lineNumber));
}
}
}
}

2
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooParser.cs

@ -168,7 +168,7 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -168,7 +168,7 @@ namespace Grunwald.BooBinding.CodeCompletion
private ICompilationUnit Parse(IProjectContent projectContent, string fileName, int[] lineLength, BooCompiler compiler)
{
compiler.Parameters.OutputWriter = new StringWriter();
compiler.Parameters.TraceSwitch.Level = System.Diagnostics.TraceLevel.Warning;
compiler.Parameters.TraceSwitch.Level = System.Diagnostics.TraceLevel.Off;
Compile compilePipe = new Compile();
BooParsingStep parsingStep = (BooParsingStep)compilePipe[0];

23
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/BooRefactoringProvider.cs

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.IO;
using ICSharpCode.SharpDevelop.Refactoring;
namespace Grunwald.BooBinding.CodeCompletion
{
public class BooRefactoringProvider : RefactoringProvider
{
public static readonly BooRefactoringProvider BooProvider = new BooRefactoringProvider();
public override bool IsEnabledForFile(string fileName)
{
return ".boo".Equals(Path.GetExtension(fileName), StringComparison.InvariantCultureIgnoreCase);
}
}
}

1
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs

@ -40,6 +40,7 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -40,6 +40,7 @@ namespace Grunwald.BooBinding.CodeCompletion
public override void Run()
{
try {
_cu.Tag = CompileUnit;
Visit(CompileUnit);
} catch (Exception ex) {
MessageService.ShowError(ex);

2
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/VariableLookupVisitor.cs

@ -65,7 +65,7 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -65,7 +65,7 @@ namespace Grunwald.BooBinding.CodeCompletion
ReferenceExpression reference = node.Left as ReferenceExpression;
if (node.Operator == BinaryOperatorType.Assign && reference != null) {
if (!(reference is MemberReferenceExpression)) {
DeclarationFound(reference.Name, null, node.Right, node.LexicalInfo);
DeclarationFound(reference.Name, null, node.Right, reference.LexicalInfo);
}
}
}

3
src/AddIns/Misc/CodeAnalysis/CodeAnalysis.addin

@ -24,7 +24,6 @@ @@ -24,7 +24,6 @@
<Path name = "/SharpDevelop/Pads/ProjectBrowser/ContextMenu/ProjectActions">
<MenuItem id = "CheckWithFxCop"
label = "${res:ICSharpCode.CodeAnalysis.CheckWithFxCop}"
class = "ICSharpCode.CodeAnalysis.CheckCurrentProjectCommand"
insertafter = "Separator2" insertbefore="SetConfiguration"/>
class = "ICSharpCode.CodeAnalysis.CheckCurrentProjectCommand"/>
</Path>
</AddIn>

18
src/AddIns/Misc/HighlightingEditor/Project/Src/Nodes/EnvironmentNode.cs

@ -25,6 +25,8 @@ namespace ICSharpCode.SharpDevelop.AddIns.HighlightingEditor.Nodes @@ -25,6 +25,8 @@ namespace ICSharpCode.SharpDevelop.AddIns.HighlightingEditor.Nodes
public string[] ColorDescs;
public EditorHighlightColor[] Colors;
const string CustomColorPrefix = "Custom$";
public EnvironmentNode(XmlElement el)
{
ArrayList envColors = new ArrayList();
@ -33,8 +35,13 @@ namespace ICSharpCode.SharpDevelop.AddIns.HighlightingEditor.Nodes @@ -33,8 +35,13 @@ namespace ICSharpCode.SharpDevelop.AddIns.HighlightingEditor.Nodes
if (el != null) {
foreach (XmlNode node in el.ChildNodes) {
if (node is XmlElement) {
envColorNames.Add(node.Name);
envColorDescriptions.Add("${res:Dialog.HighlightingEditor.EnvColors." + node.Name + "}");
if (node.Name == "Custom") {
envColorNames.Add(CustomColorPrefix + (node as XmlElement).GetAttribute("name"));
envColorDescriptions.Add((node as XmlElement).GetAttribute("name"));
} else {
envColorNames.Add(node.Name);
envColorDescriptions.Add("${res:Dialog.HighlightingEditor.EnvColors." + node.Name + "}");
}
envColors.Add(new EditorHighlightColor((XmlElement)node));
}
}
@ -66,7 +73,12 @@ namespace ICSharpCode.SharpDevelop.AddIns.HighlightingEditor.Nodes @@ -66,7 +73,12 @@ namespace ICSharpCode.SharpDevelop.AddIns.HighlightingEditor.Nodes
{
writer.WriteStartElement("Environment");
for (int i = 0; i < ColorNames.Length; i++) {
writer.WriteStartElement(ColorNames[i]);
if (ColorNames[i].StartsWith(CustomColorPrefix)) {
writer.WriteStartElement("Custom");
writer.WriteAttributeString("name", ColorNames[i].Substring(CustomColorPrefix.Length));
} else {
writer.WriteStartElement(ColorNames[i]);
}
Colors[i].WriteXmlAttributes(writer);
writer.WriteEndElement();
}

1
src/Libraries/ICSharpCode.TextEditor/Project/Resources/Boo.xshd

@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
<EOLMarkers bold="false" italic="false" color="#E0E0E5" />
<SpaceMarkers bold="false" italic="false" color="#E0E0E5" />
<TabMarkers bold="false" italic="false" color="#E0E0E5" />
<Custom name="LocalVariableCreation" bold="false" italic="false" color="#04ABAB" />
</Environment>
<Properties>

101
src/Libraries/ICSharpCode.TextEditor/Project/Resources/Mode.xsd

@ -19,102 +19,43 @@ @@ -19,102 +19,43 @@
</xsd:annotation>
<!-- Defines the default rendering of the mode -->
<xsd:complexType name="Default">
<xsd:complexType name="EnvironmentEntry">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="VRuler">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<!-- Defines the rendering of the current selection -->
<xsd:complexType name="Selection">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<!-- Defines the rendering of line numbers -->
<xsd:complexType name="LineNumbers">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="InvalidLines">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="EOLMarkers">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="SpaceMarkers">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="TabMarkers">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="CaretMarker">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="FoldLine">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="FoldMarker">
<xsd:complexType name="CustomEnvironmentEntry">
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="SelectedFoldLine">
<xsd:attribute name="bold" type="xsd:boolean" />
<xsd:attribute name="italic" type="xsd:boolean" />
<xsd:attribute name="color" type="xsd:string" />
<xsd:attribute name="bgcolor" type="xsd:string" />
</xsd:complexType>
<!-- The environment tag defines the coloring of various attributes in SharpDevelop -->
<xsd:complexType name="Environment">
<xsd:sequence>
<xsd:element name="Default" type="Default" minOccurs="0" maxOccurs="1" />
<xsd:element name="Selection" type="Selection" minOccurs="0" maxOccurs="1"/>
<xsd:element name="VRuler" type="VRuler" minOccurs="0" maxOccurs="1"/>
<xsd:element name="InvalidLines" type="InvalidLines" minOccurs="0" maxOccurs="1"/>
<xsd:element name="CaretMarker" type="CaretMarker" minOccurs="0" maxOccurs="1"/>
<xsd:element name="LineNumbers" type="LineNumbers" minOccurs="0" maxOccurs="1"/>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="Default" type="EnvironmentEntry" minOccurs="0" maxOccurs="1" />
<xsd:element name="Selection" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="VRuler" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="InvalidLines" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="CaretMarker" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="FoldLine" type="FoldLine" minOccurs="0" maxOccurs="1"/>
<xsd:element name="FoldMarker" type="FoldMarker" minOccurs="0" maxOccurs="1"/>
<xsd:element name="SelectedFoldLine" type="SelectedFoldLine" minOccurs="0" maxOccurs="1"/>
<xsd:element name="LineNumbers" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="EOLMarkers" type="EOLMarkers" minOccurs="0" maxOccurs="1"/>
<xsd:element name="SpaceMarkers" type="SpaceMarkers" minOccurs="0" maxOccurs="1"/>
<xsd:element name="TabMarkers" type="TabMarkers" minOccurs="0" maxOccurs="1"/>
<xsd:element name="FoldLine" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="FoldMarker" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="SelectedFoldLine" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:element name="EOLMarkers" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="SpaceMarkers" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="TabMarkers" type="EnvironmentEntry" minOccurs="0" maxOccurs="1"/>
<xsd:element name="Custom" type="CustomEnvironmentEntry" minOccurs="0" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="Properties">

40
src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/DefaultHighlightingStrategy.cs

@ -24,14 +24,6 @@ namespace ICSharpCode.TextEditor.Document @@ -24,14 +24,6 @@ namespace ICSharpCode.TextEditor.Document
List<HighlightRuleSet> rules = new List<HighlightRuleSet>();
Dictionary<string, HighlightColor> environmentColors = new Dictionary<string, HighlightColor>();
public IEnumerable<KeyValuePair<string, HighlightColor>> EnvironmentColors {
get {
return environmentColors;
}
}
Dictionary<string, string> properties = new Dictionary<string, string>();
string[] extensions;
@ -47,6 +39,23 @@ namespace ICSharpCode.TextEditor.Document @@ -47,6 +39,23 @@ namespace ICSharpCode.TextEditor.Document
}
}
public IEnumerable<KeyValuePair<string, HighlightColor>> EnvironmentColors {
get {
return environmentColors;
}
}
protected void ImportSettingsFrom(DefaultHighlightingStrategy source)
{
properties = source.properties;
extensions = source.extensions;
digitColor = source.digitColor;
defaultRuleSet = source.defaultRuleSet;
name = source.name;
rules = source.rules;
environmentColors = source.environmentColors;
defaultTextColor = source.defaultTextColor;
}
public DefaultHighlightingStrategy() : this("Default")
{
@ -249,11 +258,12 @@ namespace ICSharpCode.TextEditor.Document @@ -249,11 +258,12 @@ namespace ICSharpCode.TextEditor.Document
// Line state variable
protected LineSegment currentLine;
protected int currentLineNumber;
// Span stack state variable
protected Stack<Span> currentSpanStack;
public void MarkTokens(IDocument document)
public virtual void MarkTokens(IDocument document)
{
if (Rules.Count == 0) {
return;
@ -283,6 +293,7 @@ namespace ICSharpCode.TextEditor.Document @@ -283,6 +293,7 @@ namespace ICSharpCode.TextEditor.Document
return;
}
currentLineNumber = lineNumber;
List<TextWord> words = ParseLine(document);
// Alex: clear old words
if (currentLine.Words != null) {
@ -300,6 +311,7 @@ namespace ICSharpCode.TextEditor.Document @@ -300,6 +311,7 @@ namespace ICSharpCode.TextEditor.Document
bool MarkTokensInLine(IDocument document, int lineNumber, ref bool spanChanged)
{
currentLineNumber = lineNumber;
bool processNextLine = false;
LineSegment previousLine = (lineNumber > 0 ? document.GetLineSegment(lineNumber - 1) : null);
@ -396,7 +408,7 @@ namespace ICSharpCode.TextEditor.Document @@ -396,7 +408,7 @@ namespace ICSharpCode.TextEditor.Document
return processNextLine;
}
public void MarkTokens(IDocument document, List<LineSegment> inputLines)
public virtual void MarkTokens(IDocument document, List<LineSegment> inputLines)
{
if (Rules.Count == 0) {
return;
@ -645,9 +657,15 @@ namespace ICSharpCode.TextEditor.Document @@ -645,9 +657,15 @@ namespace ICSharpCode.TextEditor.Document
PushCurWord(document, ref markNext, words);
OnParsedLine(document, currentLine, words);
return words;
}
protected virtual void OnParsedLine(IDocument document, LineSegment currentLine, List<TextWord> words)
{
}
protected virtual bool OverrideSpan(string spanBegin, IDocument document, List<TextWord> words, Span span, ref int lineOffset)
{
return false;

24
src/Libraries/ICSharpCode.TextEditor/Project/Src/Document/HighlightingStrategy/HighlightingDefinitionParser.cs

@ -21,16 +21,16 @@ namespace ICSharpCode.TextEditor.Document @@ -21,16 +21,16 @@ namespace ICSharpCode.TextEditor.Document
{
static ArrayList errors = null;
public static DefaultHighlightingStrategy Parse(SyntaxMode syntaxMode, XmlTextReader xmlTextReader)
public static DefaultHighlightingStrategy Parse(SyntaxMode syntaxMode, XmlReader xmlReader)
{
return Parse(null, syntaxMode, xmlTextReader);
return Parse(null, syntaxMode, xmlReader);
}
public static DefaultHighlightingStrategy Parse(DefaultHighlightingStrategy highlighter, SyntaxMode syntaxMode, XmlTextReader xmlTextReader)
public static DefaultHighlightingStrategy Parse(DefaultHighlightingStrategy highlighter, SyntaxMode syntaxMode, XmlReader xmlReader)
{
if (syntaxMode == null)
throw new ArgumentNullException("syntaxMode");
if (xmlTextReader == null)
if (xmlReader == null)
throw new ArgumentNullException("xmlTextReader");
try {
XmlReaderSettings settings = new XmlReaderSettings();
@ -38,13 +38,13 @@ namespace ICSharpCode.TextEditor.Document @@ -38,13 +38,13 @@ namespace ICSharpCode.TextEditor.Document
settings.Schemas.Add("", new XmlTextReader(shemaStream));
settings.Schemas.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);
settings.ValidationType = ValidationType.Schema;
XmlReader validatingReader = XmlReader.Create(xmlTextReader, settings);
XmlReader validatingReader = XmlReader.Create(xmlReader, settings);
// XmlValidatingReader validatingReader = new XmlValidatingReader(xmlTextReader);
// Stream shemaStream = Assembly.GetCallingAssembly().GetManifestResourceStream("Resources.Mode.xsd");
// validatingReader.Schemas.Add("", new XmlTextReader(shemaStream));
// validatingReader.ValidationType = ValidationType.Schema;
XmlDocument doc = new XmlDocument();
doc.Load(validatingReader);
@ -70,7 +70,11 @@ namespace ICSharpCode.TextEditor.Document @@ -70,7 +70,11 @@ namespace ICSharpCode.TextEditor.Document
foreach (XmlNode node in environment.ChildNodes) {
if (node is XmlElement) {
XmlElement el = (XmlElement)node;
highlighter.SetColorFor(el.Name, el.HasAttribute("bgcolor") ? new HighlightBackground(el) : new HighlightColor(el));
if (el.Name == "Custom") {
highlighter.SetColorFor(el.GetAttribute("name"), el.HasAttribute("bgcolor") ? new HighlightBackground(el) : new HighlightColor(el));
} else {
highlighter.SetColorFor(el.Name, el.HasAttribute("bgcolor") ? new HighlightBackground(el) : new HighlightColor(el));
}
}
}
}
@ -91,20 +95,20 @@ namespace ICSharpCode.TextEditor.Document @@ -91,20 +95,20 @@ namespace ICSharpCode.TextEditor.Document
highlighter.AddRuleSet(new HighlightRuleSet(element));
}
xmlTextReader.Close();
xmlReader.Close();
if(errors!=null) {
ReportErrors(syntaxMode.FileName);
errors = null;
return null;
} else {
return highlighter;
return highlighter;
}
} catch (Exception e) {
MessageBox.Show("Could not load mode definition file '" + syntaxMode.FileName + "'.\n" + e.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
return null;
}
}
}
private static void ValidationHandler(object sender, ValidationEventArgs args)
{

9
src/Libraries/ICSharpCode.TextEditor/Project/Src/Gui/TextEditorControlBase.cs

@ -499,11 +499,10 @@ namespace ICSharpCode.TextEditor @@ -499,11 +499,10 @@ namespace ICSharpCode.TextEditor
protected TextEditorControlBase()
{
GenerateDefaultActions();
HighlightingManager.Manager.ReloadSyntaxHighlighting += new EventHandler(ReloadHighlighting);
HighlightingManager.Manager.ReloadSyntaxHighlighting += new EventHandler(OnReloadHighlighting);
}
void ReloadHighlighting(object sender, EventArgs e)
protected virtual void OnReloadHighlighting(object sender, EventArgs e)
{
if (Document.HighlightingStrategy != null) {
Document.HighlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategy(Document.HighlightingStrategy.Name);
@ -511,8 +510,6 @@ namespace ICSharpCode.TextEditor @@ -511,8 +510,6 @@ namespace ICSharpCode.TextEditor
}
}
internal IEditAction GetEditAction(Keys keyData)
{
if (!editactions.ContainsKey(keyData)) {
@ -723,7 +720,7 @@ namespace ICSharpCode.TextEditor @@ -723,7 +720,7 @@ namespace ICSharpCode.TextEditor
protected override void Dispose(bool disposing)
{
if (disposing) {
HighlightingManager.Manager.ReloadSyntaxHighlighting -= new EventHandler(ReloadHighlighting);
HighlightingManager.Manager.ReloadSyntaxHighlighting -= new EventHandler(OnReloadHighlighting);
document.HighlightingStrategy = null;
document.UndoStack.TextEditorControl = null;
}

3
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -769,6 +769,7 @@ @@ -769,6 +769,7 @@
<Compile Include="Src\Services\RefactoringService\NRefactoryRefactoringProvider.cs" />
<Compile Include="Src\Services\RefactoringService\NamespaceRefactoringService.cs" />
<Compile Include="Src\Services\RefactoringService\RefactorMenu.cs" />
<Compile Include="Src\TextEditor\Gui\Editor\ParserHighlightingStrategy.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Libraries\DockPanel_Src\WinFormsUI\WinFormsUI.csproj">
@ -797,4 +798,4 @@ @@ -797,4 +798,4 @@
<Folder Include="Src\Gui\Pads\ClassBrowser\NodeBuilder" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
</Project>
</Project>

10
src/Main/Base/Project/Src/Services/ParserService/ParseInformationEventHandler.cs

@ -59,12 +59,14 @@ namespace ICSharpCode.Core @@ -59,12 +59,14 @@ namespace ICSharpCode.Core
string fileName;
string content;
bool updated;
ParseInformation parseInformation;
public ParserUpdateStepEventArgs(string fileName, string content, bool updated)
public ParserUpdateStepEventArgs(string fileName, string content, bool updated, ParseInformation parseInformation)
{
this.fileName = fileName;
this.content = content;
this.updated = updated;
this.parseInformation = parseInformation;
}
public string FileName {
@ -82,5 +84,11 @@ namespace ICSharpCode.Core @@ -82,5 +84,11 @@ namespace ICSharpCode.Core
return updated;
}
}
public ParseInformation ParseInformation {
get {
return parseInformation;
}
}
}
}

2
src/Main/Base/Project/Src/Services/ParserService/ParserService.cs

@ -344,7 +344,7 @@ namespace ICSharpCode.Core @@ -344,7 +344,7 @@ namespace ICSharpCode.Core
((IParseInformationListener)editable).ParseInformationUpdated(parseInformation);
}
}
OnParserUpdateStepFinished(new ParserUpdateStepEventArgs(fileName, text, updated));
OnParserUpdateStepFinished(new ParserUpdateStepEventArgs(fileName, text, updated, parseInformation));
}
}
}

11
src/Main/Base/Project/Src/Services/RefactoringService/NRefactoryRefactoringProvider.cs

@ -19,6 +19,17 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -19,6 +19,17 @@ namespace ICSharpCode.SharpDevelop.Refactoring
{
public static readonly NRefactoryRefactoringProvider NRefactoryProviderInstance = new NRefactoryRefactoringProvider();
public override bool IsEnabledForFile(string fileName)
{
string extension = Path.GetExtension(fileName);
if (extension.Equals(".cs", StringComparison.InvariantCultureIgnoreCase))
return true;
else if (extension.Equals(".vb", StringComparison.InvariantCultureIgnoreCase))
return true;
else
return false;
}
#region FindUnusedUsingDeclarations
protected class PossibleTypeReference
{

15
src/Main/Base/Project/Src/Services/RefactoringService/RefactorMenu.cs

@ -37,13 +37,20 @@ namespace ICSharpCode.SharpDevelop.Refactoring @@ -37,13 +37,20 @@ namespace ICSharpCode.SharpDevelop.Refactoring
return false;
}
ITextEditorControlProvider provider = WorkbenchSingleton.Workbench.ActiveWorkbenchWindow.ActiveViewContent as ITextEditorControlProvider;
if (provider == null) return false;
if (provider == null)
return false;
LanguageProperties language = ParserService.CurrentProjectContent.Language;
if (language == null) return false;
if (language == null)
return false;
string supports = condition.Properties["supports"];
if (supports == "*") return true;
RefactoringProvider rp = language.RefactoringProvider;
if (!rp.IsEnabledForFile(provider.TextEditorControl.FileName))
return false;
string supports = condition.Properties["supports"];
if (supports == "*")
return true;
Type t = rp.GetType();
try {
return (bool)t.InvokeMember("Supports" + supports, BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty, null, rp, null);

14
src/Main/Base/Project/Src/Services/RefactoringService/RefactoringProvider.cs

@ -11,15 +11,25 @@ using ICSharpCode.SharpDevelop.Dom; @@ -11,15 +11,25 @@ using ICSharpCode.SharpDevelop.Dom;
namespace ICSharpCode.SharpDevelop.Refactoring
{
public class RefactoringProvider
public abstract class RefactoringProvider
{
/// <summary>
/// A RefactoringProvider instance that supports no refactorings.
/// </summary>
public static readonly RefactoringProvider DummyProvider = new RefactoringProvider();
public static readonly RefactoringProvider DummyProvider = new DummyRefactoringProvider();
protected RefactoringProvider() {}
public abstract bool IsEnabledForFile(string fileName);
private class DummyRefactoringProvider : RefactoringProvider
{
public override bool IsEnabledForFile(string fileName)
{
return false;
}
}
public virtual bool SupportsFindUnusedUsingDeclarations {
get {
return false;

3
src/Main/Base/Project/Src/TextEditor/Commands/TextAreaContextmenuCommands.cs

@ -69,6 +69,9 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands @@ -69,6 +69,9 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands
throw new Exception("Strategy can't be null");
}
control.Document.HighlightingStrategy = strat;
if (control is SharpDevelopTextAreaControl) {
((SharpDevelopTextAreaControl)control).InitializeAdvancedHighlighter();
}
control.Refresh();
}
}

101
src/Main/Base/Project/Src/TextEditor/Gui/Editor/ParserHighlightingStrategy.cs

@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Xml;
using System.Windows.Forms;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
{
public interface IAdvancedHighlighter : IDisposable
{
/// <summary>
/// Is called once after creating the highlighter. Gives your highlighter a chance
/// to register events on the text editor.
/// </summary>
void Initialize(TextEditorControl textEditor);
/// <summary>
/// Gives your highlighter the chance to change the highlighting of the words.
/// </summary>
void MarkLine(IDocument document, LineSegment currentLine, List<TextWord> words);
/// <summary>
/// When your class fires this event, MarkLine will be called for all waiting lines.
/// You can fire this event on any thread, but MarkLine will be called on that thread
/// - so if you use multithreading, you must invoke when accessing the document inside
/// MarkLine.
/// </summary>
event EventHandler MarkOutstandingRequests;
}
internal class ParserHighlightingStrategy : DefaultHighlightingStrategy
{
readonly object lockObject = new object();
readonly IAdvancedHighlighter highlighter;
IDocument document;
Dictionary<LineSegment, List<TextWord>> outstanding = new Dictionary<LineSegment, List<TextWord>>();
public ParserHighlightingStrategy(DefaultHighlightingStrategy baseStrategy, IAdvancedHighlighter highlighter)
{
ImportSettingsFrom(baseStrategy);
this.highlighter = highlighter;
highlighter.MarkOutstandingRequests += OnMarkOutstandingRequest;
}
int directMark; // counter for immediate marking when only few lines have changed
public override void MarkTokens(IDocument document)
{
lock (lockObject) {
outstanding.Clear();
}
base.MarkTokens(document);
}
public override void MarkTokens(IDocument document, List<LineSegment> inputLines)
{
directMark = (inputLines.Count < 3) ? inputLines.Count : 0;
base.MarkTokens(document, inputLines);
directMark = 0;
}
protected override void OnParsedLine(IDocument document, LineSegment currentLine, List<TextWord> words)
{
int ln = currentLineNumber;
if (directMark > 0) {
directMark--;
highlighter.MarkLine(document, currentLine, words);
} else {
this.document = document;
lock (lockObject) {
outstanding[currentLine] = words;
}
}
}
void OnMarkOutstandingRequest(object sender, EventArgs e)
{
Dictionary<LineSegment, List<TextWord>> oldOutstanding;
lock (lockObject) {
oldOutstanding = outstanding;
outstanding = new Dictionary<LineSegment, List<TextWord>>();
}
// We cannot call MarkLine inside lock(lockObject) because then the main
// thread could deadlock with the highlighter thread.
foreach (KeyValuePair<LineSegment, List<TextWord>> pair in oldOutstanding) {
highlighter.MarkLine(document, pair.Key, pair.Value);
}
}
}
}

46
src/Main/Base/Project/Src/TextEditor/Gui/Editor/SharpDevelopTextAreaControl.cs

@ -6,23 +6,18 @@ @@ -6,23 +6,18 @@
// </file>
using System;
using System.IO;
using System.Collections;
using System.Drawing;
using System.Diagnostics;
using System.Collections.Generic;
using System.Windows.Forms;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.DefaultEditor.Actions;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Internal.Templates;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Actions;
using ICSharpCode.SharpDevelop.Internal.Templates;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.TextEditor.Gui.InsightWindow;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Gui.CompletionWindow;
using System.Threading;
using ICSharpCode.TextEditor.Gui.InsightWindow;
namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
{
@ -31,9 +26,11 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -31,9 +26,11 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
readonly static string contextMenuPath = "/SharpDevelop/ViewContent/DefaultTextEditor/ContextMenu";
readonly static string editActionsPath = "/AddIns/DefaultTextEditor/EditActions";
readonly static string formatingStrategyPath = "/AddIns/DefaultTextEditor/Formatter";
readonly static string advancedHighlighterPath = "/AddIns/DefaultTextEditor/AdvancedHighlighter";
QuickClassBrowserPanel quickClassBrowserPanel = null;
ErrorDrawer errorDrawer;
IAdvancedHighlighter advancedHighlighter;
public QuickClassBrowserPanel QuickClassBrowserPanel {
get {
@ -99,6 +96,10 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -99,6 +96,10 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
quickClassBrowserPanel.Dispose();
quickClassBrowserPanel = null;
}
if (advancedHighlighter != null) {
advancedHighlighter.Dispose();
advancedHighlighter = null;
}
CloseCodeCompletionWindow(this, EventArgs.Empty);
CloseInsightWindow(this, EventArgs.Empty);
}
@ -388,6 +389,29 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -388,6 +389,29 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
TextEditorProperties.IndentStyle = save2;
}
protected override void OnReloadHighlighting(object sender, EventArgs e)
{
base.OnReloadHighlighting(sender, e);
InitializeAdvancedHighlighter();
}
public void InitializeAdvancedHighlighter()
{
if (advancedHighlighter != null) {
advancedHighlighter.Dispose();
advancedHighlighter = null;
}
string highlighterPath = advancedHighlighterPath + "/" + Document.HighlightingStrategy.Name;
if (AddInTree.ExistsTreeNode(highlighterPath)) {
IList<IAdvancedHighlighter> highlighter = AddInTree.BuildItems<IAdvancedHighlighter>(highlighterPath, this);
if (highlighter != null && highlighter.Count > 0) {
advancedHighlighter = highlighter[0];
Document.HighlightingStrategy = new ParserHighlightingStrategy((DefaultHighlightingStrategy)Document.HighlightingStrategy, advancedHighlighter);
advancedHighlighter.Initialize(this);
}
}
}
public void InitializeFormatter()
{
string formatterPath = formatingStrategyPath + "/" + Document.HighlightingStrategy.Name;

3
src/Main/Base/Project/Src/TextEditor/Gui/Editor/TextEditorDisplayBinding.cs

@ -59,9 +59,11 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -59,9 +59,11 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
b2.textAreaControl.Dock = DockStyle.Fill;
b2.Load(fileName);
b2.textAreaControl.Document.HighlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategyForFile(fileName);
b2.textAreaControl.InitializeAdvancedHighlighter();
b2.textAreaControl.InitializeFormatter();
b2.ForceFoldingUpdate();
b2.textAreaControl.ActivateQuickClassBrowserOnDemand();
return b2;
}
@ -71,6 +73,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -71,6 +73,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
b2.textAreaControl.Document.TextContent = StringParser.Parse(content);
b2.textAreaControl.Document.HighlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategy(language);
b2.textAreaControl.InitializeAdvancedHighlighter();
b2.textAreaControl.InitializeFormatter();
b2.textAreaControl.ActivateQuickClassBrowserOnDemand();
return b2;

Loading…
Cancel
Save