From fc8a05358a92cc3c77c5f1e30d536807ef0614fd Mon Sep 17 00:00:00 2001 From: Victoria Plitt Date: Mon, 8 Apr 2019 13:49:55 +0300 Subject: were added scripting projects --- .../Highlighting/DocumentHighlighter.cs | 468 +++++++++++++++++++++ .../Highlighting/HighlightedInlineBuilder.cs | 214 ++++++++++ .../Highlighting/HighlightedLine.cs | 154 +++++++ .../Highlighting/HighlightedSection.cs | 33 ++ .../Highlighting/HighlightingBrush.cs | 117 ++++++ .../Highlighting/HighlightingColor.cs | 119 ++++++ .../Highlighting/HighlightingColorizer.cs | 286 +++++++++++++ .../HighlightingDefinitionInvalidException.cs | 43 ++ .../HighlightingDefinitionTypeConverter.cs | 54 +++ .../Highlighting/HighlightingManager.cs | 290 +++++++++++++ .../Highlighting/HighlightingRule.cs | 31 ++ .../Highlighting/HighlightingRuleSet.cs | 46 ++ .../Highlighting/HighlightingSpan.cs | 64 +++ .../Highlighting/HtmlClipboard.cs | 201 +++++++++ .../Highlighting/IHighlighter.cs | 35 ++ .../Highlighting/IHighlightingDefinition.cs | 54 +++ .../IHighlightingDefinitionReferenceResolver.cs | 18 + .../Highlighting/OffsetColorizer.cs | 39 ++ .../Highlighting/Resources/ASPX.xshd | 16 + .../Highlighting/Resources/Boo.xshd | 212 ++++++++++ .../Highlighting/Resources/CPP-Mode.xshd | 195 +++++++++ .../Highlighting/Resources/CSS-Mode.xshd | 57 +++ .../Highlighting/Resources/CSharp-Mode.xshd | 311 ++++++++++++++ .../Highlighting/Resources/Coco-Mode.xshd | 74 ++++ .../Highlighting/Resources/HTML-Mode.xshd | 388 +++++++++++++++++ .../Highlighting/Resources/Java-Mode.xshd | 152 +++++++ .../Highlighting/Resources/JavaScript-Mode.xshd | 132 ++++++ .../Highlighting/Resources/MarkDown-Mode.xshd | 56 +++ .../Highlighting/Resources/ModeV1.xsd | 296 +++++++++++++ .../Highlighting/Resources/ModeV2.xsd | 167 ++++++++ .../Highlighting/Resources/PHP-Mode.xshd | 158 +++++++ .../Highlighting/Resources/Patch-Mode.xshd | 35 ++ .../Highlighting/Resources/PowerShell.xshd | 146 +++++++ .../Highlighting/Resources/Resources.cs | 48 +++ .../Highlighting/Resources/Tex-Mode.xshd | 108 +++++ .../Highlighting/Resources/VBNET-Mode.xshd | 256 +++++++++++ .../Highlighting/Resources/XML-Mode.xshd | 63 +++ .../Highlighting/Resources/XmlDoc.xshd | 57 +++ .../Highlighting/Xshd/HighlightingLoader.cs | 99 +++++ .../Highlighting/Xshd/IXshdVisitor.cs | 32 ++ .../Highlighting/Xshd/SaveXshdVisitor.cs | 182 ++++++++ .../Highlighting/Xshd/V1Loader.cs | 325 ++++++++++++++ .../Highlighting/Xshd/V2Loader.cs | 334 +++++++++++++++ .../Highlighting/Xshd/XmlHighlightingDefinition.cs | 406 ++++++++++++++++++ .../Highlighting/Xshd/XshdColor.cs | 97 +++++ .../Highlighting/Xshd/XshdElement.cs | 29 ++ .../Highlighting/Xshd/XshdImport.cs | 25 ++ .../Highlighting/Xshd/XshdKeywords.cs | 36 ++ .../Highlighting/Xshd/XshdProperty.cs | 38 ++ .../Highlighting/Xshd/XshdReference.cs | 127 ++++++ .../Highlighting/Xshd/XshdRule.cs | 35 ++ .../Highlighting/Xshd/XshdRuleSet.cs | 51 +++ .../Highlighting/Xshd/XshdSpan.cs | 82 ++++ .../Highlighting/Xshd/XshdSyntaxDefinition.cs | 50 +++ 54 files changed, 7141 insertions(+) create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/DocumentHighlighter.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedInlineBuilder.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedLine.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedSection.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingBrush.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingColor.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingColorizer.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingDefinitionInvalidException.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingDefinitionTypeConverter.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingManager.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingRule.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingRuleSet.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingSpan.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HtmlClipboard.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlighter.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlightingDefinition.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlightingDefinitionReferenceResolver.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ASPX.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Boo.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CPP-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSS-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Coco-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/HTML-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Java-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/JavaScript-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ModeV1.xsd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ModeV2.xsd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/PHP-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Patch-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/PowerShell.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Resources.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Tex-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/VBNET-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XmlDoc.xshd create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/HighlightingLoader.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/IXshdVisitor.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/SaveXshdVisitor.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/V1Loader.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/V2Loader.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XmlHighlightingDefinition.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdColor.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdElement.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdImport.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdKeywords.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdProperty.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdReference.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdRule.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdRuleSet.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdSpan.cs create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdSyntaxDefinition.cs (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting') diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/DocumentHighlighter.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/DocumentHighlighter.cs new file mode 100644 index 000000000..393c0a930 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/DocumentHighlighter.cs @@ -0,0 +1,468 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text.RegularExpressions; + +using Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Utils; +using SpanStack = Tango.Scripting.Editors.Utils.ImmutableStack; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// This class can syntax-highlight a document. + /// It automatically manages invalidating the highlighting when the document changes. + /// + public class DocumentHighlighter : ILineTracker, IHighlighter + { + /// + /// Stores the span state at the end of each line. + /// storedSpanStacks[0] = state at beginning of document + /// storedSpanStacks[i] = state after line i + /// + readonly CompressingTreeList storedSpanStacks = new CompressingTreeList(object.ReferenceEquals); + readonly CompressingTreeList isValid = new CompressingTreeList((a, b) => a == b); + readonly TextDocument document; + readonly HighlightingRuleSet baseRuleSet; + bool isHighlighting; + + /// + /// Gets the document that this DocumentHighlighter is highlighting. + /// + public TextDocument Document { + get { return document; } + } + + /// + /// Creates a new DocumentHighlighter instance. + /// + public DocumentHighlighter(TextDocument document, HighlightingRuleSet baseRuleSet) + { + if (document == null) + throw new ArgumentNullException("document"); + if (baseRuleSet == null) + throw new ArgumentNullException("baseRuleSet"); + this.document = document; + this.baseRuleSet = baseRuleSet; + WeakLineTracker.Register(document, this); + InvalidateHighlighting(); + } + + void ILineTracker.BeforeRemoveLine(DocumentLine line) + { + CheckIsHighlighting(); + int number = line.LineNumber; + storedSpanStacks.RemoveAt(number); + isValid.RemoveAt(number); + if (number < isValid.Count) { + isValid[number] = false; + if (number < firstInvalidLine) + firstInvalidLine = number; + } + } + + void ILineTracker.SetLineLength(DocumentLine line, int newTotalLength) + { + CheckIsHighlighting(); + int number = line.LineNumber; + isValid[number] = false; + if (number < firstInvalidLine) + firstInvalidLine = number; + } + + void ILineTracker.LineInserted(DocumentLine insertionPos, DocumentLine newLine) + { + CheckIsHighlighting(); + Debug.Assert(insertionPos.LineNumber + 1 == newLine.LineNumber); + int lineNumber = newLine.LineNumber; + storedSpanStacks.Insert(lineNumber, null); + isValid.Insert(lineNumber, false); + if (lineNumber < firstInvalidLine) + firstInvalidLine = lineNumber; + } + + void ILineTracker.RebuildDocument() + { + InvalidateHighlighting(); + } + + ImmutableStack initialSpanStack = SpanStack.Empty; + + /// + /// Gets/sets the the initial span stack of the document. Default value is . + /// + public ImmutableStack InitialSpanStack { + get { return initialSpanStack; } + set { + if (value == null) + initialSpanStack = SpanStack.Empty; + else + initialSpanStack = value; + InvalidateHighlighting(); + } + } + + /// + /// Invalidates all stored highlighting info. + /// When the document changes, the highlighting is invalidated automatically, this method + /// needs to be called only when there are changes to the highlighting rule set. + /// + public void InvalidateHighlighting() + { + CheckIsHighlighting(); + storedSpanStacks.Clear(); + storedSpanStacks.Add(initialSpanStack); + storedSpanStacks.InsertRange(1, document.LineCount, null); + isValid.Clear(); + isValid.Add(true); + isValid.InsertRange(1, document.LineCount, false); + firstInvalidLine = 1; + } + + int firstInvalidLine; + + /// + /// Highlights the specified document line. + /// + /// The line to highlight. + /// A line object that represents the highlighted sections. + [ObsoleteAttribute("Use the (int lineNumber) overload instead")] + public HighlightedLine HighlightLine(DocumentLine line) + { + if (!document.Lines.Contains(line)) + throw new ArgumentException("The specified line does not belong to the document."); + return HighlightLine(line.LineNumber); + } + + /// + public HighlightedLine HighlightLine(int lineNumber) + { + ThrowUtil.CheckInRangeInclusive(lineNumber, "lineNumber", 1, document.LineCount); + CheckIsHighlighting(); + isHighlighting = true; + try { + HighlightUpTo(lineNumber); + DocumentLine line = document.GetLineByNumber(lineNumber); + highlightedLine = new HighlightedLine(document, line); + HighlightLineAndUpdateTreeList(line, lineNumber); + return highlightedLine; + } finally { + highlightedLine = null; + isHighlighting = false; + } + } + + /// + public SpanStack GetSpanStack(int lineNumber) + { + ThrowUtil.CheckInRangeInclusive(lineNumber, "lineNumber", 0, document.LineCount); + if (firstInvalidLine <= lineNumber) { + CheckIsHighlighting(); + isHighlighting = true; + try { + HighlightUpTo(lineNumber + 1); + } finally { + isHighlighting = false; + } + } + return storedSpanStacks[lineNumber]; + } + + void CheckIsHighlighting() + { + if (isHighlighting) { + throw new InvalidOperationException("Invalid call - a highlighting operation is currently running."); + } + } + + void HighlightUpTo(int targetLineNumber) + { + Debug.Assert(highlightedLine == null); // ensure this method is only used for + while (firstInvalidLine < targetLineNumber) { + HighlightLineAndUpdateTreeList(document.GetLineByNumber(firstInvalidLine), firstInvalidLine); + } + } + + void HighlightLineAndUpdateTreeList(DocumentLine line, int lineNumber) + { + //Debug.WriteLine("Highlight line " + lineNumber + (highlightedLine != null ? "" : " (span stack only)")); + spanStack = storedSpanStacks[lineNumber - 1]; + HighlightLineInternal(line); + if (!EqualSpanStacks(spanStack, storedSpanStacks[lineNumber])) { + isValid[lineNumber] = true; + //Debug.WriteLine("Span stack in line " + lineNumber + " changed from " + storedSpanStacks[lineNumber] + " to " + spanStack); + storedSpanStacks[lineNumber] = spanStack; + if (lineNumber + 1 < isValid.Count) { + isValid[lineNumber + 1] = false; + firstInvalidLine = lineNumber + 1; + } else { + firstInvalidLine = int.MaxValue; + } + OnHighlightStateChanged(line, lineNumber); + } else if (firstInvalidLine == lineNumber) { + isValid[lineNumber] = true; + firstInvalidLine = isValid.IndexOf(false); + if (firstInvalidLine < 0) + firstInvalidLine = int.MaxValue; + } + } + + static bool EqualSpanStacks(SpanStack a, SpanStack b) + { + // We must use value equality between the stacks because TextViewDocumentHighlighter.OnHighlightStateChanged + // depends on the fact that equal input state + unchanged line contents produce equal output state. + if (a == b) + return true; + if (a == null || b == null) + return false; + while (!a.IsEmpty && !b.IsEmpty) { + if (a.Peek() != b.Peek()) + return false; + a = a.Pop(); + b = b.Pop(); + if (a == b) + return true; + } + return a.IsEmpty && b.IsEmpty; + } + + /// + /// Is called when the highlighting state at the end of the specified line has changed. + /// + /// This callback must not call HighlightLine or InvalidateHighlighting. + /// It may call GetSpanStack, but only for the changed line and lines above. + /// This method must not modify the document. + protected virtual void OnHighlightStateChanged(DocumentLine line, int lineNumber) + { + } + + #region Highlighting Engine + SpanStack spanStack; + + // local variables from HighlightLineInternal (are member because they are accessed by HighlighLine helper methods) + string lineText; + int lineStartOffset; + int position; + + /// + /// the HighlightedLine where highlighting output is being written to. + /// if this variable is null, nothing is highlighted and only the span state is updated + /// + HighlightedLine highlightedLine; + + void HighlightLineInternal(DocumentLine line) + { + lineStartOffset = line.Offset; + lineText = document.GetText(line.Offset, line.Length); + position = 0; + ResetColorStack(); + HighlightingRuleSet currentRuleSet = this.CurrentRuleSet; + Stack storedMatchArrays = new Stack(); + Match[] matches = AllocateMatchArray(currentRuleSet.Spans.Count); + Match endSpanMatch = null; + + while (true) { + for (int i = 0; i < matches.Length; i++) { + if (matches[i] == null || (matches[i].Success && matches[i].Index < position)) + matches[i] = currentRuleSet.Spans[i].StartExpression.Match(lineText, position); + } + if (endSpanMatch == null && !spanStack.IsEmpty) + endSpanMatch = spanStack.Peek().EndExpression.Match(lineText, position); + + Match firstMatch = Minimum(matches, endSpanMatch); + if (firstMatch == null) + break; + + HighlightNonSpans(firstMatch.Index); + + Debug.Assert(position == firstMatch.Index); + + if (firstMatch == endSpanMatch) { + HighlightingSpan poppedSpan = spanStack.Peek(); + if (!poppedSpan.SpanColorIncludesEnd) + PopColor(); // pop SpanColor + PushColor(poppedSpan.EndColor); + position = firstMatch.Index + firstMatch.Length; + PopColor(); // pop EndColor + if (poppedSpan.SpanColorIncludesEnd) + PopColor(); // pop SpanColor + spanStack = spanStack.Pop(); + currentRuleSet = this.CurrentRuleSet; + //FreeMatchArray(matches); + if (storedMatchArrays.Count > 0) { + matches = storedMatchArrays.Pop(); + int index = currentRuleSet.Spans.IndexOf(poppedSpan); + Debug.Assert(index >= 0 && index < matches.Length); + if (matches[index].Index == position) { + throw new InvalidOperationException( + "A highlighting span matched 0 characters, which would cause an endless loop.\n" + + "Change the highlighting definition so that either the start or the end regex matches at least one character.\n" + + "Start regex: " + poppedSpan.StartExpression + "\n" + + "End regex: " + poppedSpan.EndExpression); + } + } else { + matches = AllocateMatchArray(currentRuleSet.Spans.Count); + } + } else { + int index = Array.IndexOf(matches, firstMatch); + Debug.Assert(index >= 0); + HighlightingSpan newSpan = currentRuleSet.Spans[index]; + spanStack = spanStack.Push(newSpan); + currentRuleSet = this.CurrentRuleSet; + storedMatchArrays.Push(matches); + matches = AllocateMatchArray(currentRuleSet.Spans.Count); + if (newSpan.SpanColorIncludesStart) + PushColor(newSpan.SpanColor); + PushColor(newSpan.StartColor); + position = firstMatch.Index + firstMatch.Length; + PopColor(); + if (!newSpan.SpanColorIncludesStart) + PushColor(newSpan.SpanColor); + } + endSpanMatch = null; + } + HighlightNonSpans(line.Length); + + PopAllColors(); + } + + void HighlightNonSpans(int until) + { + Debug.Assert(position <= until); + if (position == until) + return; + if (highlightedLine != null) { + IList rules = CurrentRuleSet.Rules; + Match[] matches = AllocateMatchArray(rules.Count); + while (true) { + for (int i = 0; i < matches.Length; i++) { + if (matches[i] == null || (matches[i].Success && matches[i].Index < position)) + matches[i] = rules[i].Regex.Match(lineText, position, until - position); + } + Match firstMatch = Minimum(matches, null); + if (firstMatch == null) + break; + + position = firstMatch.Index; + int ruleIndex = Array.IndexOf(matches, firstMatch); + if (firstMatch.Length == 0) { + throw new InvalidOperationException( + "A highlighting rule matched 0 characters, which would cause an endless loop.\n" + + "Change the highlighting definition so that the rule matches at least one character.\n" + + "Regex: " + rules[ruleIndex].Regex); + } + PushColor(rules[ruleIndex].Color); + position = firstMatch.Index + firstMatch.Length; + PopColor(); + } + //FreeMatchArray(matches); + } + position = until; + } + + static readonly HighlightingRuleSet emptyRuleSet = new HighlightingRuleSet() { Name = "EmptyRuleSet" }; + + HighlightingRuleSet CurrentRuleSet { + get { + if (spanStack.IsEmpty) + return baseRuleSet; + else + return spanStack.Peek().RuleSet ?? emptyRuleSet; + } + } + #endregion + + #region Color Stack Management + Stack highlightedSectionStack; + HighlightedSection lastPoppedSection; + + void ResetColorStack() + { + Debug.Assert(position == 0); + lastPoppedSection = null; + if (highlightedLine == null) { + highlightedSectionStack = null; + } else { + highlightedSectionStack = new Stack(); + foreach (HighlightingSpan span in spanStack.Reverse()) { + PushColor(span.SpanColor); + } + } + } + + void PushColor(HighlightingColor color) + { + if (highlightedLine == null) + return; + if (color == null) { + highlightedSectionStack.Push(null); + } else if (lastPoppedSection != null && lastPoppedSection.Color == color + && lastPoppedSection.Offset + lastPoppedSection.Length == position + lineStartOffset) + { + highlightedSectionStack.Push(lastPoppedSection); + lastPoppedSection = null; + } else { + HighlightedSection hs = new HighlightedSection { + Offset = position + lineStartOffset, + Color = color + }; + highlightedLine.Sections.Add(hs); + highlightedSectionStack.Push(hs); + lastPoppedSection = null; + } + } + + void PopColor() + { + if (highlightedLine == null) + return; + HighlightedSection s = highlightedSectionStack.Pop(); + if (s != null) { + s.Length = (position + lineStartOffset) - s.Offset; + if (s.Length == 0) + highlightedLine.Sections.Remove(s); + else + lastPoppedSection = s; + } + } + + void PopAllColors() + { + if (highlightedSectionStack != null) { + while (highlightedSectionStack.Count > 0) + PopColor(); + } + } + #endregion + + #region Match helpers + /// + /// Returns the first match from the array or endSpanMatch. + /// + static Match Minimum(Match[] arr, Match endSpanMatch) + { + Match min = null; + foreach (Match v in arr) { + if (v.Success && (min == null || v.Index < min.Index)) + min = v; + } + if (endSpanMatch != null && endSpanMatch.Success && (min == null || endSpanMatch.Index < min.Index)) + return endSpanMatch; + else + return min; + } + + static Match[] AllocateMatchArray(int count) + { + if (count == 0) + return Empty.Array; + else + return new Match[count]; + } + #endregion + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedInlineBuilder.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedInlineBuilder.cs new file mode 100644 index 000000000..ccfce3d49 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedInlineBuilder.cs @@ -0,0 +1,214 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Windows; +using System.Windows.Documents; +using System.Windows.Media; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// Takes a series of highlighting commands and stores them. + /// Later, it can build inline objects (for use with WPF TextBlock) from the commands. + /// + /// + /// This class is not used in AvalonEdit - but it is useful for someone who wants to put a HighlightedLine + /// into a TextBlock. + /// In SharpDevelop, we use it to provide syntax highlighting inside the search results pad. + /// + public sealed class HighlightedInlineBuilder + { + sealed class HighlightingState + { + internal Brush Foreground; + internal Brush Background; + internal FontFamily Family; + internal FontWeight? Weight; + internal FontStyle? Style; + + public HighlightingState Clone() + { + return new HighlightingState { + Foreground = this.Foreground, + Background = this.Background, + Family = this.Family, + Weight = this.Weight, + Style = this.Style + }; + } + } + + readonly string text; + List stateChangeOffsets = new List(); + List stateChanges = new List(); + + int GetIndexForOffset(int offset) + { + if (offset < 0 || offset > text.Length) + throw new ArgumentOutOfRangeException("offset"); + int index = stateChangeOffsets.BinarySearch(offset); + if (index < 0) { + index = ~index; + if (offset < text.Length) { + stateChanges.Insert(index, stateChanges[index - 1].Clone()); + stateChangeOffsets.Insert(index, offset); + } + } + return index; + } + + /// + /// Creates a new HighlightedInlineBuilder instance. + /// + public HighlightedInlineBuilder(string text) + { + if (text == null) + throw new ArgumentNullException("text"); + this.text = text; + stateChangeOffsets.Add(0); + stateChanges.Add(new HighlightingState()); + } + + HighlightedInlineBuilder(string text, int[] offsets, HighlightingState[] states) + { + this.text = text; + stateChangeOffsets.AddRange(offsets); + stateChanges.AddRange(states); + } + + /// + /// Gets the text. + /// + public string Text { + get { return text; } + } + + /// + /// Applies the properties from the HighlightingColor to the specified text segment. + /// + public void SetHighlighting(int offset, int length, HighlightingColor color) + { + if (color == null) + throw new ArgumentNullException("color"); + if (color.Foreground == null && color.FontStyle == null && color.FontWeight == null) { + // Optimization: don't split the HighlightingState when we're not changing + // any property. For example, the "Punctuation" color in C# is + // empty by default. + return; + } + int startIndex = GetIndexForOffset(offset); + int endIndex = GetIndexForOffset(offset + length); + for (int i = startIndex; i < endIndex; i++) { + HighlightingState state = stateChanges[i]; + if (color.Foreground != null) + state.Foreground = color.Foreground.GetBrush(null); + if (color.Background != null) + state.Background = color.Background.GetBrush(null); + if (color.FontStyle != null) + state.Style = color.FontStyle; + if (color.FontWeight != null) + state.Weight = color.FontWeight; + } + } + + /// + /// Sets the foreground brush on the specified text segment. + /// + public void SetForeground(int offset, int length, Brush brush) + { + int startIndex = GetIndexForOffset(offset); + int endIndex = GetIndexForOffset(offset + length); + for (int i = startIndex; i < endIndex; i++) { + stateChanges[i].Foreground = brush; + } + } + + /// + /// Sets the background brush on the specified text segment. + /// + public void SetBackground(int offset, int length, Brush brush) + { + int startIndex = GetIndexForOffset(offset); + int endIndex = GetIndexForOffset(offset + length); + for (int i = startIndex; i < endIndex; i++) { + stateChanges[i].Background = brush; + } + } + + /// + /// Sets the font weight on the specified text segment. + /// + public void SetFontWeight(int offset, int length, FontWeight weight) + { + int startIndex = GetIndexForOffset(offset); + int endIndex = GetIndexForOffset(offset + length); + for (int i = startIndex; i < endIndex; i++) { + stateChanges[i].Weight = weight; + } + } + + /// + /// Sets the font style on the specified text segment. + /// + public void SetFontStyle(int offset, int length, FontStyle style) + { + int startIndex = GetIndexForOffset(offset); + int endIndex = GetIndexForOffset(offset + length); + for (int i = startIndex; i < endIndex; i++) { + stateChanges[i].Style = style; + } + } + + /// + /// Sets the font family on the specified text segment. + /// + public void SetFontFamily(int offset, int length, FontFamily family) + { + int startIndex = GetIndexForOffset(offset); + int endIndex = GetIndexForOffset(offset + length); + for (int i = startIndex; i < endIndex; i++) { + stateChanges[i].Family = family; + } + } + + /// + /// Creates WPF Run instances that can be used for TextBlock.Inlines. + /// + public Run[] CreateRuns() + { + Run[] runs = new Run[stateChanges.Count]; + for (int i = 0; i < runs.Length; i++) { + int startOffset = stateChangeOffsets[i]; + int endOffset = i + 1 < stateChangeOffsets.Count ? stateChangeOffsets[i + 1] : text.Length; + Run r = new Run(text.Substring(startOffset, endOffset - startOffset)); + HighlightingState state = stateChanges[i]; + if (state.Foreground != null) + r.Foreground = state.Foreground; + if (state.Background != null) + r.Background = state.Background; + if (state.Weight != null) + r.FontWeight = state.Weight.Value; + if (state.Family != null) + r.FontFamily = state.Family; + if (state.Style != null) + r.FontStyle = state.Style.Value; + runs[i] = r; + } + return runs; + } + + /// + /// Clones this HighlightedInlineBuilder. + /// + public HighlightedInlineBuilder Clone() + { + return new HighlightedInlineBuilder(this.text, + stateChangeOffsets.ToArray(), + stateChanges.Select(sc => sc.Clone()).ToArray()); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedLine.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedLine.cs new file mode 100644 index 000000000..e6932c0aa --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedLine.cs @@ -0,0 +1,154 @@ +// 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.Globalization; +using System.IO; +using System.Text; + +using Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// Represents a highlighted document line. + /// + public class HighlightedLine + { + /// + /// Creates a new HighlightedLine instance. + /// + public HighlightedLine(TextDocument document, DocumentLine documentLine) + { + if (document == null) + throw new ArgumentNullException("document"); + if (!document.Lines.Contains(documentLine)) + throw new ArgumentException("Line is null or not part of document"); + this.Document = document; + this.DocumentLine = documentLine; + this.Sections = new NullSafeCollection(); + } + + /// + /// Gets the document associated with this HighlightedLine. + /// + public TextDocument Document { get; private set; } + + /// + /// Gets the document line associated with this HighlightedLine. + /// + public DocumentLine DocumentLine { get; private set; } + + /// + /// Gets the highlighted sections. + /// The sections are not overlapping, but they may be nested. + /// In that case, outer sections come in the list before inner sections. + /// The sections are sorted by start offset. + /// + public IList Sections { get; private set; } + + /// + /// Gets the default color of all text outside a . + /// + public HighlightingColor DefaultTextColor { get; set; } + + sealed class HtmlElement : IComparable + { + internal readonly int Offset; + internal readonly int Nesting; + internal readonly bool IsEnd; + internal readonly HighlightingColor Color; + + public HtmlElement(int offset, int nesting, bool isEnd, HighlightingColor color) + { + this.Offset = offset; + this.Nesting = nesting; + this.IsEnd = isEnd; + this.Color = color; + } + + public int CompareTo(HtmlElement other) + { + int r = Offset.CompareTo(other.Offset); + if (r != 0) + return r; + if (IsEnd != other.IsEnd) { + if (IsEnd) + return -1; + else + return 1; + } else { + if (IsEnd) + return other.Nesting.CompareTo(Nesting); + else + return Nesting.CompareTo(other.Nesting); + } + } + } + + /// + /// Produces HTML code for the line, with <span class="colorName"> tags. + /// + public string ToHtml(HtmlOptions options) + { + int startOffset = this.DocumentLine.Offset; + return ToHtml(startOffset, startOffset + this.DocumentLine.Length, options); + } + + /// + /// Produces HTML code for a section of the line, with <span class="colorName"> tags. + /// + public string ToHtml(int startOffset, int endOffset, HtmlOptions options) + { + if (options == null) + throw new ArgumentNullException("options"); + int documentLineStartOffset = this.DocumentLine.Offset; + int documentLineEndOffset = documentLineStartOffset + this.DocumentLine.Length; + if (startOffset < documentLineStartOffset || startOffset > documentLineEndOffset) + throw new ArgumentOutOfRangeException("startOffset", startOffset, "Value must be between " + documentLineStartOffset + " and " + documentLineEndOffset); + if (endOffset < startOffset || endOffset > documentLineEndOffset) + throw new ArgumentOutOfRangeException("endOffset", endOffset, "Value must be between startOffset and " + documentLineEndOffset); + ISegment requestedSegment = new SimpleSegment(startOffset, endOffset - startOffset); + + List elements = new List(); + for (int i = 0; i < this.Sections.Count; i++) { + HighlightedSection s = this.Sections[i]; + if (s.GetOverlap(requestedSegment).Length > 0) { + elements.Add(new HtmlElement(s.Offset, i, false, s.Color)); + elements.Add(new HtmlElement(s.Offset + s.Length, i, true, s.Color)); + } + } + elements.Sort(); + + TextDocument document = this.Document; + StringWriter w = new StringWriter(CultureInfo.InvariantCulture); + int textOffset = startOffset; + foreach (HtmlElement e in elements) { + int newOffset = Math.Min(e.Offset, endOffset); + if (newOffset > startOffset) { + HtmlClipboard.EscapeHtml(w, document.GetText(textOffset, newOffset - textOffset), options); + } + textOffset = Math.Max(textOffset, newOffset); + if (options.ColorNeedsSpanForStyling(e.Color)) { + if (e.IsEnd) { + w.Write(""); + } else { + w.Write("'); + } + } + } + HtmlClipboard.EscapeHtml(w, document.GetText(textOffset, endOffset - textOffset), options); + return w.ToString(); + } + + /// + public override string ToString() + { + return "[" + GetType().Name + " " + ToHtml(new HtmlOptions()) + "]"; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedSection.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedSection.cs new file mode 100644 index 000000000..9e6fb56f1 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightedSection.cs @@ -0,0 +1,33 @@ +// 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 Tango.Scripting.Editors.Document; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// A text section with syntax highlighting information. + /// + public class HighlightedSection : ISegment + { + /// + /// Gets/sets the document offset of the section. + /// + public int Offset { get; set; } + + /// + /// Gets/sets the length of the section. + /// + public int Length { get; set; } + + int ISegment.EndOffset { + get { return this.Offset + this.Length; } + } + + /// + /// Gets the highlighting color associated with the highlighted section. + /// + public HighlightingColor Color { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingBrush.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingBrush.cs new file mode 100644 index 000000000..2e99013f3 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingBrush.cs @@ -0,0 +1,117 @@ +// 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.Diagnostics; +using System.Globalization; +using System.Reflection; +using System.Runtime.Serialization; +using System.Windows; +using System.Windows.Media; + +using Tango.Scripting.Editors.Rendering; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// A brush used for syntax highlighting. Can retrieve a real brush on-demand. + /// + [Serializable] + public abstract class HighlightingBrush + { + /// + /// Gets the real brush. + /// + /// The construction context. context can be null! + public abstract Brush GetBrush(ITextRunConstructionContext context); + + /// + /// Gets the color of the brush. + /// + /// The construction context. context can be null! + public virtual Color? GetColor(ITextRunConstructionContext context) + { + SolidColorBrush scb = GetBrush(context) as SolidColorBrush; + if (scb != null) + return scb.Color; + else + return null; + } + } + + /// + /// Highlighting brush implementation that takes a frozen brush. + /// + [Serializable] + sealed class SimpleHighlightingBrush : HighlightingBrush, ISerializable + { + readonly SolidColorBrush brush; + + public SimpleHighlightingBrush(SolidColorBrush brush) + { + brush.Freeze(); + this.brush = brush; + } + + public SimpleHighlightingBrush(Color color) : this(new SolidColorBrush(color)) {} + + public override Brush GetBrush(ITextRunConstructionContext context) + { + return brush; + } + + public override string ToString() + { + return brush.ToString(); + } + + SimpleHighlightingBrush(SerializationInfo info, StreamingContext context) + { + this.brush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(info.GetString("color"))); + brush.Freeze(); + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("color", brush.Color.ToString(CultureInfo.InvariantCulture)); + } + } + + /// + /// HighlightingBrush implementation that finds a brush using a resource. + /// + [Serializable] + sealed class SystemColorHighlightingBrush : HighlightingBrush, ISerializable + { + readonly PropertyInfo property; + + public SystemColorHighlightingBrush(PropertyInfo property) + { + Debug.Assert(property.ReflectedType == typeof(SystemColors)); + Debug.Assert(typeof(Brush).IsAssignableFrom(property.PropertyType)); + this.property = property; + } + + public override Brush GetBrush(ITextRunConstructionContext context) + { + return (Brush)property.GetValue(null, null); + } + + public override string ToString() + { + return property.Name; + } + + SystemColorHighlightingBrush(SerializationInfo info, StreamingContext context) + { + property = typeof(SystemColors).GetProperty(info.GetString("propertyName")); + if (property == null) + throw new ArgumentException("Error deserializing SystemColorHighlightingBrush"); + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("propertyName", property.Name); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingColor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingColor.cs new file mode 100644 index 000000000..f1b1a25c8 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingColor.cs @@ -0,0 +1,119 @@ +// 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.Globalization; +using System.Runtime.Serialization; +using System.Security.Permissions; +using System.Text; +using System.Windows; +using System.Windows.Media; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// A highlighting color is a set of font properties and foreground and background color. + /// + [Serializable] + public class HighlightingColor : ISerializable + { + /// + /// Gets/Sets the name of the color. + /// + public string Name { get; set; } + + /// + /// Gets/sets the font weight. Null if the highlighting color does not change the font weight. + /// + public FontWeight? FontWeight { get; set; } + + /// + /// Gets/sets the font style. Null if the highlighting color does not change the font style. + /// + public FontStyle? FontStyle { get; set; } + + /// + /// Gets/sets the foreground color applied by the highlighting. + /// + public HighlightingBrush Foreground { get; set; } + + /// + /// Gets/sets the background color applied by the highlighting. + /// + public HighlightingBrush Background { get; set; } + + /// + /// Creates a new HighlightingColor instance. + /// + public HighlightingColor() + { + } + + /// + /// Deserializes a HighlightingColor. + /// + protected HighlightingColor(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + this.Name = info.GetString("Name"); + if (info.GetBoolean("HasWeight")) + this.FontWeight = System.Windows.FontWeight.FromOpenTypeWeight(info.GetInt32("Weight")); + if (info.GetBoolean("HasStyle")) + this.FontStyle = (FontStyle?)new FontStyleConverter().ConvertFromInvariantString(info.GetString("Style")); + this.Foreground = (HighlightingBrush)info.GetValue("Foreground", typeof(HighlightingBrush)); + this.Background = (HighlightingBrush)info.GetValue("Background", typeof(HighlightingBrush)); + } + + /// + /// Serializes this HighlightingColor instance. + /// + [System.Security.SecurityCritical] + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + info.AddValue("Name", this.Name); + info.AddValue("HasWeight", this.FontWeight.HasValue); + if (this.FontWeight.HasValue) + info.AddValue("Weight", this.FontWeight.Value.ToOpenTypeWeight()); + info.AddValue("HasStyle", this.FontStyle.HasValue); + if (this.FontStyle.HasValue) + info.AddValue("Style", this.FontStyle.Value.ToString()); + info.AddValue("Foreground", this.Foreground); + info.AddValue("Background", this.Background); + } + + /// + /// Gets CSS code for the color. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "CSS usually uses lowercase, and all possible values are English-only")] + public virtual string ToCss() + { + StringBuilder b = new StringBuilder(); + if (Foreground != null) { + Color? c = Foreground.GetColor(null); + if (c != null) { + b.AppendFormat(CultureInfo.InvariantCulture, "color: #{0:x2}{1:x2}{2:x2}; ", c.Value.R, c.Value.G, c.Value.B); + } + } + if (FontWeight != null) { + b.Append("font-weight: "); + b.Append(FontWeight.Value.ToString().ToLowerInvariant()); + b.Append("; "); + } + if (FontStyle != null) { + b.Append("font-style: "); + b.Append(FontStyle.Value.ToString().ToLowerInvariant()); + b.Append("; "); + } + return b.ToString(); + } + + /// + public override string ToString() + { + return "[" + GetType() + " " + (string.IsNullOrEmpty(this.Name) ? ToCss() : this.Name) + "]"; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingColorizer.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingColorizer.cs new file mode 100644 index 000000000..9dfcc3976 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingColorizer.cs @@ -0,0 +1,286 @@ +// 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.Diagnostics; +using System.Windows; +using System.Windows.Media; +using System.Windows.Threading; + +using Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Rendering; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// A colorizes that interprets a highlighting rule set and colors the document accordingly. + /// + public class HighlightingColorizer : DocumentColorizingTransformer + { + readonly HighlightingRuleSet ruleSet; + + /// + /// Creates a new HighlightingColorizer instance. + /// + /// The root highlighting rule set. + public HighlightingColorizer(HighlightingRuleSet ruleSet) + { + if (ruleSet == null) + throw new ArgumentNullException("ruleSet"); + this.ruleSet = ruleSet; + } + + /// + /// This constructor is obsolete - please use the other overload instead. + /// + /// UNUSED + /// The root highlighting rule set. + [Obsolete("The TextView parameter is no longer used, please use the constructor taking only HighlightingRuleSet instead")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "textView")] + public HighlightingColorizer(TextView textView, HighlightingRuleSet ruleSet) + : this(ruleSet) + { + } + + void textView_DocumentChanged(object sender, EventArgs e) + { + OnDocumentChanged((TextView)sender); + } + + void OnDocumentChanged(TextView textView) + { + // remove existing highlighter, if any exists + textView.Services.RemoveService(typeof(IHighlighter)); + textView.Services.RemoveService(typeof(DocumentHighlighter)); + + TextDocument document = textView.Document; + if (document != null) { + IHighlighter highlighter = CreateHighlighter(textView, document); + textView.Services.AddService(typeof(IHighlighter), highlighter); + // for backward compatiblity, we're registering using both the interface and concrete types + if (highlighter is DocumentHighlighter) + textView.Services.AddService(typeof(DocumentHighlighter), highlighter); + } + } + + /// + /// Creates the IHighlighter instance for the specified text document. + /// + protected virtual IHighlighter CreateHighlighter(TextView textView, TextDocument document) + { + return new TextViewDocumentHighlighter(this, textView, document, ruleSet); + } + + /// + protected override void OnAddToTextView(TextView textView) + { + base.OnAddToTextView(textView); + textView.DocumentChanged += textView_DocumentChanged; + textView.VisualLineConstructionStarting += textView_VisualLineConstructionStarting; + OnDocumentChanged(textView); + } + + /// + protected override void OnRemoveFromTextView(TextView textView) + { + base.OnRemoveFromTextView(textView); + textView.Services.RemoveService(typeof(IHighlighter)); + textView.Services.RemoveService(typeof(DocumentHighlighter)); + textView.DocumentChanged -= textView_DocumentChanged; + textView.VisualLineConstructionStarting -= textView_VisualLineConstructionStarting; + } + + void textView_VisualLineConstructionStarting(object sender, VisualLineConstructionStartEventArgs e) + { + IHighlighter highlighter = ((TextView)sender).Services.GetService(typeof(IHighlighter)) as IHighlighter; + if (highlighter != null) { + // Force update of highlighting state up to the position where we start generating visual lines. + // This is necessary in case the document gets modified above the FirstLineInView so that the highlighting state changes. + // We need to detect this case and issue a redraw (through TextViewDocumentHighligher.OnHighlightStateChanged) + // before the visual line construction reuses existing lines that were built using the invalid highlighting state. + lineNumberBeingColorized = e.FirstLineInView.LineNumber - 1; + highlighter.GetSpanStack(lineNumberBeingColorized); + lineNumberBeingColorized = 0; + } + } + + DocumentLine lastColorizedLine; + + /// + protected override void Colorize(ITextRunConstructionContext context) + { + this.lastColorizedLine = null; + base.Colorize(context); + if (this.lastColorizedLine != context.VisualLine.LastDocumentLine) { + IHighlighter highlighter = context.TextView.Services.GetService(typeof(IHighlighter)) as IHighlighter; + if (highlighter != null) { + // In some cases, it is possible that we didn't highlight the last document line within the visual line + // (e.g. when the line ends with a fold marker). + // But even if we didn't highlight it, we'll have to update the highlighting state for it so that the + // proof inside TextViewDocumentHighlighter.OnHighlightStateChanged holds. + lineNumberBeingColorized = context.VisualLine.LastDocumentLine.LineNumber; + highlighter.GetSpanStack(lineNumberBeingColorized); + lineNumberBeingColorized = 0; + } + } + this.lastColorizedLine = null; + } + + int lineNumberBeingColorized; + + /// + protected override void ColorizeLine(DocumentLine line) + { + IHighlighter highlighter = CurrentContext.TextView.Services.GetService(typeof(IHighlighter)) as IHighlighter; + if (highlighter != null) { + lineNumberBeingColorized = line.LineNumber; + HighlightedLine hl = highlighter.HighlightLine(lineNumberBeingColorized); + lineNumberBeingColorized = 0; + foreach (HighlightedSection section in hl.Sections) { + if (IsEmptyColor(section.Color)) + continue; + ChangeLinePart(section.Offset, section.Offset + section.Length, + visualLineElement => ApplyColorToElement(visualLineElement, section.Color)); + } + } + this.lastColorizedLine = line; + } + + /// + /// Gets whether the color is empty (has no effect on a VisualLineTextElement). + /// For example, the C# "Punctuation" is an empty color. + /// + bool IsEmptyColor(HighlightingColor color) + { + if (color == null) + return true; + return color.Background == null && color.Foreground == null + && color.FontStyle == null && color.FontWeight == null; + } + + /// + /// Applies a highlighting color to a visual line element. + /// + protected virtual void ApplyColorToElement(VisualLineElement element, HighlightingColor color) + { + if (color.Foreground != null) { + Brush b = color.Foreground.GetBrush(CurrentContext); + if (b != null) + element.TextRunProperties.SetForegroundBrush(b); + } + if (color.Background != null) { + Brush b = color.Background.GetBrush(CurrentContext); + if (b != null) + element.BackgroundBrush = b; + } + if (color.FontStyle != null || color.FontWeight != null) { + Typeface tf = element.TextRunProperties.Typeface; + element.TextRunProperties.SetTypeface(new Typeface( + tf.FontFamily, + color.FontStyle ?? tf.Style, + color.FontWeight ?? tf.Weight, + tf.Stretch + )); + } + } + + /// + /// This class is responsible for telling the TextView to redraw lines when the highlighting state has changed. + /// + /// + /// Creation of a VisualLine triggers the syntax highlighter (which works on-demand), so it says: + /// Hey, the user typed "/*". Don't just recreate that line, but also the next one + /// because my highlighting state (at end of line) changed! + /// + sealed class TextViewDocumentHighlighter : DocumentHighlighter + { + readonly HighlightingColorizer colorizer; + readonly TextView textView; + + public TextViewDocumentHighlighter(HighlightingColorizer colorizer, TextView textView, TextDocument document, HighlightingRuleSet baseRuleSet) + : base(document, baseRuleSet) + { + Debug.Assert(colorizer != null); + Debug.Assert(textView != null); + this.colorizer = colorizer; + this.textView = textView; + } + + protected override void OnHighlightStateChanged(DocumentLine line, int lineNumber) + { + base.OnHighlightStateChanged(line, lineNumber); + if (colorizer.lineNumberBeingColorized != lineNumber) { + // Ignore notifications for any line except the one we're interested in. + // This improves the performance as Redraw() can take quite some time when called repeatedly + // while scanning the document (above the visible area) for highlighting changes. + return; + } + if (textView.Document != this.Document) { + // May happen if document on text view was changed but some user code is still using the + // existing IHighlighter instance. + return; + } + + // The user may have inserted "/*" into the current line, and so far only that line got redrawn. + // So when the highlighting state is changed, we issue a redraw for the line immediately below. + // If the highlighting state change applies to the lines below, too, the construction of each line + // will invalidate the next line, and the construction pass will regenerate all lines. + + //Debug.WriteLine("OnHighlightStateChanged forces redraw of line " + (lineNumber + 1)); + + // If the VisualLine construction is in progress, we have to avoid sending redraw commands for + // anything above the line currently being constructed. + // It takes some explanation to see why this cannot happen. + // VisualLines always get constructed from top to bottom. + // Each VisualLine construction calls into the highlighter and thus forces an update of the + // highlighting state for all lines up to the one being constructed. + + // To guarantee that we don't redraw lines we just constructed, we need to show that when + // a VisualLine is being reused, the highlighting state at that location is still up-to-date. + + // This isn't exactly trivial and the initial implementation was incorrect in the presence of external document changes + // (e.g. split view). + + // For the first line in the view, the TextView.VisualLineConstructionStarting event is used to check that the + // highlighting state is up-to-date. If it isn't, this method will be executed, and it'll mark the first line + // in the view as requiring a redraw. This is safely possible because that event occurs before any lines are reused. + + // Once we take care of the first visual line, we won't get in trouble with other lines due to the top-to-bottom + // construction process. + + // We'll prove that: if line N is being reused, then the highlighting state is up-to-date until (end of) line N-1. + + // Start of induction: the first line in view is reused only if the highlighting state was up-to-date + // until line N-1 (no change detected in VisualLineConstructionStarting event). + + // Induction step: + // If another line N+1 is being reused, then either + // a) the previous line (the visual line containing document line N) was newly constructed + // or b) the previous line was reused + // In case a, the construction updated the highlighting state. This means the stack at end of line N is up-to-date. + // In case b, the highlighting state at N-1 was up-to-date, and the text of line N was not changed. + // (if the text was changed, the line could not have been reused). + // From this follows that the highlighting state at N is still up-to-date. + + // The above proof holds even in the presence of folding: folding only ever hides text in the middle of a visual line. + // Our Colorize-override ensures that the highlighting state is always updated for the LastDocumentLine, + // so it will always invalidate the next visual line when a folded line is constructed + // and the highlighting stack has changed. + + textView.Redraw(line.NextLine, DispatcherPriority.Normal); + + /* + * Meta-comment: "why does this have to be so complicated?" + * + * The problem is that I want to re-highlight only on-demand and incrementally; + * and at the same time only repaint changed lines. + * So the highlighter and the VisualLine construction both have to run in a single pass. + * The highlighter must take care that it never touches already constructed visual lines; + * if it detects that something must be redrawn because the highlighting state changed, + * it must do so early enough in the construction process. + * But doing it too early means it doesn't have the information necessary to re-highlight and redraw only the desired parts. + */ + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingDefinitionInvalidException.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingDefinitionInvalidException.cs new file mode 100644 index 000000000..dccd6a481 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingDefinitionInvalidException.cs @@ -0,0 +1,43 @@ +// 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.Runtime.Serialization; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// Indicates that the highlighting definition that was tried to load was invalid. + /// + [Serializable()] + public class HighlightingDefinitionInvalidException : Exception + { + /// + /// Creates a new HighlightingDefinitionInvalidException instance. + /// + public HighlightingDefinitionInvalidException() : base() + { + } + + /// + /// Creates a new HighlightingDefinitionInvalidException instance. + /// + public HighlightingDefinitionInvalidException(string message) : base(message) + { + } + + /// + /// Creates a new HighlightingDefinitionInvalidException instance. + /// + public HighlightingDefinitionInvalidException(string message, Exception innerException) : base(message, innerException) + { + } + + /// + /// Creates a new HighlightingDefinitionInvalidException instance. + /// + protected HighlightingDefinitionInvalidException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingDefinitionTypeConverter.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingDefinitionTypeConverter.cs new file mode 100644 index 000000000..7463d9353 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingDefinitionTypeConverter.cs @@ -0,0 +1,54 @@ +// 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.ComponentModel; +using System.Globalization; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// Converts between strings and by treating the string as the definition name + /// and calling HighlightingManager.Instance.GetDefinition(name). + /// + public sealed class HighlightingDefinitionTypeConverter : TypeConverter + { + /// + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + return true; + else + return base.CanConvertFrom(context, sourceType); + } + + /// + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + string definitionName = value as string; + if (definitionName != null) + return HighlightingManager.Instance.GetDefinition(definitionName); + else + return base.ConvertFrom(context, culture, value); + } + + /// + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + return true; + else + return base.CanConvertTo(context, destinationType); + } + + /// + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + IHighlightingDefinition definition = value as IHighlightingDefinition; + if (definition != null && destinationType == typeof(string)) + return definition.Name; + else + return base.ConvertTo(context, culture, value, destinationType); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingManager.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingManager.cs new file mode 100644 index 000000000..8db4787d7 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingManager.cs @@ -0,0 +1,290 @@ +// 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.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Xml; + +using Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// Manages a list of syntax highlighting definitions. + /// + /// + /// All memers on this class (including instance members) are thread-safe. + /// + public class HighlightingManager : IHighlightingDefinitionReferenceResolver + { + sealed class DelayLoadedHighlightingDefinition : IHighlightingDefinition2 + { + readonly object lockObj = new object(); + readonly string name; + Func lazyLoadingFunction; + IHighlightingDefinition definition; + Exception storedException; + + public DelayLoadedHighlightingDefinition(string name, Func lazyLoadingFunction) + { + this.name = name; + this.lazyLoadingFunction = lazyLoadingFunction; + } + + public string Name { + get { + if (name != null) + return name; + else + return GetDefinition().Name; + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", + Justification = "The exception will be rethrown")] + IHighlightingDefinition GetDefinition() + { + Func func; + lock (lockObj) { + if (this.definition != null) + return this.definition; + func = this.lazyLoadingFunction; + } + Exception exception = null; + IHighlightingDefinition def = null; + try { + using (var busyLock = BusyManager.Enter(this)) { + if (!busyLock.Success) + throw new InvalidOperationException("Tried to create delay-loaded highlighting definition recursively. Make sure the are no cyclic references between the highlighting definitions."); + def = func(); + } + if (def == null) + throw new InvalidOperationException("Function for delay-loading highlighting definition returned null"); + } catch (Exception ex) { + exception = ex; + } + lock (lockObj) { + this.lazyLoadingFunction = null; + if (this.definition == null && this.storedException == null) { + this.definition = def; + this.storedException = exception; + } + if (this.storedException != null) + throw new HighlightingDefinitionInvalidException("Error delay-loading highlighting definition", this.storedException); + return this.definition; + } + } + + public HighlightingRuleSet MainRuleSet { + get { + return GetDefinition().MainRuleSet; + } + } + + public HighlightingRuleSet GetNamedRuleSet(string name) + { + return GetDefinition().GetNamedRuleSet(name); + } + + public HighlightingColor GetNamedColor(string name) + { + return GetDefinition().GetNamedColor(name); + } + + public IEnumerable NamedHighlightingColors { + get { + return GetDefinition().NamedHighlightingColors; + } + } + + public override string ToString() + { + return this.Name; + } + + public IDictionary Properties { + get { + var def = GetDefinition() as IHighlightingDefinition2; + if (def != null) + return def.Properties; + return null; + } + } + } + + readonly object lockObj = new object(); + Dictionary highlightingsByName = new Dictionary(); + Dictionary highlightingsByExtension = new Dictionary(StringComparer.OrdinalIgnoreCase); + List allHighlightings = new List(); + + /// + /// Gets a highlighting definition by name. + /// Returns null if the definition is not found. + /// + public IHighlightingDefinition GetDefinition(string name) + { + lock (lockObj) { + IHighlightingDefinition rh; + if (highlightingsByName.TryGetValue(name, out rh)) + return rh; + else + return null; + } + } + + /// + /// Gets a copy of all highlightings. + /// + public ReadOnlyCollection HighlightingDefinitions { + get { + lock (lockObj) { + return Array.AsReadOnly(allHighlightings.ToArray()); + } + } + } + + /// + /// Gets the names of the registered highlightings. + /// + [ObsoleteAttribute("Use the HighlightingDefinitions property instead.")] + public IEnumerable HighlightingNames { + get { + lock (lockObj) { + return new List(highlightingsByName.Keys); + } + } + } + + /// + /// Gets a highlighting definition by extension. + /// Returns null if the definition is not found. + /// + public IHighlightingDefinition GetDefinitionByExtension(string extension) + { + lock (lockObj) { + IHighlightingDefinition rh; + if (highlightingsByExtension.TryGetValue(extension, out rh)) + return rh; + else + return null; + } + } + + /// + /// Registers a highlighting definition. + /// + /// The name to register the definition with. + /// The file extensions to register the definition for. + /// The highlighting definition. + public void RegisterHighlighting(string name, string[] extensions, IHighlightingDefinition highlighting) + { + if (highlighting == null) + throw new ArgumentNullException("highlighting"); + + lock (lockObj) { + allHighlightings.Add(highlighting); + if (name != null) { + highlightingsByName[name] = highlighting; + } + if (extensions != null) { + foreach (string ext in extensions) { + highlightingsByExtension[ext] = highlighting; + } + } + } + } + + /// + /// Registers a highlighting definition. + /// + /// The name to register the definition with. + /// The file extensions to register the definition for. + /// A function that loads the highlighting definition. + public void RegisterHighlighting(string name, string[] extensions, Func lazyLoadedHighlighting) + { + if (lazyLoadedHighlighting == null) + throw new ArgumentNullException("lazyLoadedHighlighting"); + RegisterHighlighting(name, extensions, new DelayLoadedHighlightingDefinition(name, lazyLoadedHighlighting)); + } + + /// + /// Gets the default HighlightingManager instance. + /// The default HighlightingManager comes with built-in highlightings. + /// + public static HighlightingManager Instance { + get { + return DefaultHighlightingManager.Instance; + } + } + + internal sealed class DefaultHighlightingManager : HighlightingManager + { + public new static readonly DefaultHighlightingManager Instance = new DefaultHighlightingManager(); + + public DefaultHighlightingManager() + { + Resources.RegisterBuiltInHighlightings(this); + } + + // Registering a built-in highlighting + internal void RegisterHighlighting(string name, string[] extensions, string resourceName) + { + try { + #if DEBUG + // don't use lazy-loading in debug builds, show errors immediately + Xshd.XshdSyntaxDefinition xshd; + using (Stream s = Resources.OpenStream(resourceName)) { + using (XmlTextReader reader = new XmlTextReader(s)) { + xshd = Xshd.HighlightingLoader.LoadXshd(reader, false); + } + } + Debug.Assert(name == xshd.Name); + if (extensions != null) + Debug.Assert(System.Linq.Enumerable.SequenceEqual(extensions, xshd.Extensions)); + else + Debug.Assert(xshd.Extensions.Count == 0); + + // round-trip xshd: +// string resourceFileName = Path.Combine(Path.GetTempPath(), resourceName); +// using (XmlTextWriter writer = new XmlTextWriter(resourceFileName, System.Text.Encoding.UTF8)) { +// writer.Formatting = Formatting.Indented; +// new Xshd.SaveXshdVisitor(writer).WriteDefinition(xshd); +// } +// using (FileStream fs = File.Create(resourceFileName + ".bin")) { +// new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter().Serialize(fs, xshd); +// } +// using (FileStream fs = File.Create(resourceFileName + ".compiled")) { +// new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter().Serialize(fs, Xshd.HighlightingLoader.Load(xshd, this)); +// } + + RegisterHighlighting(name, extensions, Xshd.HighlightingLoader.Load(xshd, this)); + #else + RegisterHighlighting(name, extensions, LoadHighlighting(resourceName)); + #endif + } catch (HighlightingDefinitionInvalidException ex) { + throw new InvalidOperationException("The built-in highlighting '" + name + "' is invalid.", ex); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", + Justification = "LoadHighlighting is used only in release builds")] + Func LoadHighlighting(string resourceName) + { + Func func = delegate { + Xshd.XshdSyntaxDefinition xshd; + using (Stream s = Resources.OpenStream(resourceName)) { + using (XmlTextReader reader = new XmlTextReader(s)) { + // in release builds, skip validating the built-in highlightings + xshd = Xshd.HighlightingLoader.LoadXshd(reader, true); + } + } + return Xshd.HighlightingLoader.Load(xshd, this); + }; + return func; + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingRule.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingRule.cs new file mode 100644 index 000000000..18edf4974 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingRule.cs @@ -0,0 +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) + +using System; +using System.Text.RegularExpressions; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// A highlighting rule. + /// + [Serializable] + public class HighlightingRule + { + /// + /// Gets/Sets the regular expression for the rule. + /// + public Regex Regex { get; set; } + + /// + /// Gets/Sets the highlighting color. + /// + public HighlightingColor Color { get; set; } + + /// + public override string ToString() + { + return "[" + GetType().Name + " " + Regex + "]"; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingRuleSet.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingRuleSet.cs new file mode 100644 index 000000000..f887b9d54 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingRuleSet.cs @@ -0,0 +1,46 @@ +// 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 Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// A highlighting rule set describes a set of spans that are valid at a given code location. + /// + [Serializable] + public class HighlightingRuleSet + { + /// + /// Creates a new RuleSet instance. + /// + public HighlightingRuleSet() + { + this.Spans = new NullSafeCollection(); + this.Rules = new NullSafeCollection(); + } + + /// + /// Gets/Sets the name of the rule set. + /// + public string Name { get; set; } + + /// + /// Gets the list of spans. + /// + public IList Spans { get; private set; } + + /// + /// Gets the list of rules. + /// + public IList Rules { get; private set; } + + /// + public override string ToString() + { + return "[" + GetType().Name + " " + Name + "]"; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingSpan.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingSpan.cs new file mode 100644 index 000000000..b57e70a93 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HighlightingSpan.cs @@ -0,0 +1,64 @@ +// 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.Text.RegularExpressions; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// A highlighting span is a region with start+end expression that has a different RuleSet inside + /// and colors the region. + /// + [Serializable] + public class HighlightingSpan + { + /// + /// Gets/Sets the start expression. + /// + public Regex StartExpression { get; set; } + + /// + /// Gets/Sets the end expression. + /// + public Regex EndExpression { get; set; } + + /// + /// Gets/Sets the rule set that applies inside this span. + /// + public HighlightingRuleSet RuleSet { get; set; } + + /// + /// Gets the color used for the text matching the start expression. + /// + public HighlightingColor StartColor { get; set; } + + /// + /// Gets the color used for the text between start and end. + /// + public HighlightingColor SpanColor { get; set; } + + /// + /// Gets the color used for the text matching the end expression. + /// + public HighlightingColor EndColor { get; set; } + + /// + /// Gets/Sets whether the span color includes the start. + /// The default is false. + /// + public bool SpanColorIncludesStart { get; set; } + + /// + /// Gets/Sets whether the span color includes the end. + /// The default is false. + /// + public bool SpanColorIncludesEnd { get; set; } + + /// + public override string ToString() + { + return "[" + GetType().Name + " Start=" + StartExpression + ", End=" + EndExpression + "]"; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HtmlClipboard.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HtmlClipboard.cs new file mode 100644 index 000000000..a656308b7 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/HtmlClipboard.cs @@ -0,0 +1,201 @@ +// 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.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; +using System.Windows; + +using Tango.Scripting.Editors.Document; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// Allows copying HTML text to the clipboard. + /// + public static class HtmlClipboard + { + /// + /// Builds a header for the CF_HTML clipboard format. + /// + static string BuildHeader(int startHTML, int endHTML, int startFragment, int endFragment) + { + StringBuilder b = new StringBuilder(); + b.AppendLine("Version:0.9"); + b.AppendLine("StartHTML:" + startHTML.ToString("d8", CultureInfo.InvariantCulture)); + b.AppendLine("EndHTML:" + endHTML.ToString("d8", CultureInfo.InvariantCulture)); + b.AppendLine("StartFragment:" + startFragment.ToString("d8", CultureInfo.InvariantCulture)); + b.AppendLine("EndFragment:" + endFragment.ToString("d8", CultureInfo.InvariantCulture)); + return b.ToString(); + } + + /// + /// Sets the TextDataFormat.Html on the data object to the specified html fragment. + /// This helper methods takes care of creating the necessary CF_HTML header. + /// + public static void SetHtml(DataObject dataObject, string htmlFragment) + { + if (dataObject == null) + throw new ArgumentNullException("dataObject"); + if (htmlFragment == null) + throw new ArgumentNullException("htmlFragment"); + + string htmlStart = @"" + Environment.NewLine + + "" + Environment.NewLine + + "" + Environment.NewLine + + "" + Environment.NewLine; + string htmlEnd = "" + Environment.NewLine + "" + Environment.NewLine + "" + Environment.NewLine; + string dummyHeader = BuildHeader(0, 0, 0, 0); + // the offsets are stored as UTF-8 bytes (see CF_HTML documentation) + int startHTML = dummyHeader.Length; + int startFragment = startHTML + htmlStart.Length; + int endFragment = startFragment + Encoding.UTF8.GetByteCount(htmlFragment); + int endHTML = endFragment + htmlEnd.Length; + string cf_html = BuildHeader(startHTML, endHTML, startFragment, endFragment) + htmlStart + htmlFragment + htmlEnd; + Debug.WriteLine(cf_html); + dataObject.SetText(cf_html, TextDataFormat.Html); + } + + /// + /// Creates a HTML fragment from a part of a document. + /// + /// The document to create HTML from. + /// The highlighter used to highlight the document. null is valid and will create HTML without any highlighting. + /// The part of the document to create HTML for. You can pass null to create HTML for the whole document. + /// The options for the HTML creation. + /// HTML code for the document part. + public static string CreateHtmlFragment(TextDocument document, IHighlighter highlighter, ISegment segment, HtmlOptions options) + { + if (document == null) + throw new ArgumentNullException("document"); + if (options == null) + throw new ArgumentNullException("options"); + if (highlighter != null && highlighter.Document != document) + throw new ArgumentException("Highlighter does not belong to the specified document."); + if (segment == null) + segment = new SimpleSegment(0, document.TextLength); + + StringBuilder html = new StringBuilder(); + int segmentEndOffset = segment.EndOffset; + DocumentLine line = document.GetLineByOffset(segment.Offset); + while (line != null && line.Offset < segmentEndOffset) { + HighlightedLine highlightedLine; + if (highlighter != null) + highlightedLine = highlighter.HighlightLine(line.LineNumber); + else + highlightedLine = new HighlightedLine(document, line); + SimpleSegment s = segment.GetOverlap(line); + if (html.Length > 0) + html.AppendLine("
"); + html.Append(highlightedLine.ToHtml(s.Offset, s.EndOffset, options)); + line = line.NextLine; + } + return html.ToString(); + } + + /// + /// Escapes text and writes the result to the StringBuilder. + /// + internal static void EscapeHtml(StringWriter w, string text, HtmlOptions options) + { + int spaceCount = -1; + foreach (char c in text) { + if (c == ' ') { + if (spaceCount < 0) + w.Write(" "); + else + spaceCount++; + } else if (c == '\t') { + if (spaceCount < 0) + spaceCount = 0; + spaceCount += options.TabSize; + } else { + if (spaceCount == 1) { + w.Write(' '); + } else if (spaceCount >= 1) { + for (int i = 0; i < spaceCount; i++) { + w.Write(" "); + } + } + spaceCount = 0; + switch (c) { + case '<': + w.Write("<"); + break; + case '>': + w.Write(">"); + break; + case '&': + w.Write("&"); + break; + case '"': + w.Write("""); + break; + default: + w.Write(c); + break; + } + } + } + for (int i = 0; i < spaceCount; i++) { + w.Write(" "); + } + } + } + + /// + /// Holds options for converting text to HTML. + /// + public class HtmlOptions + { + /// + /// Creates a default HtmlOptions instance. + /// + public HtmlOptions() + { + this.TabSize = 4; + } + + /// + /// Creates a new HtmlOptions instance that copies applicable options from the . + /// + public HtmlOptions(TextEditorOptions options) + : this() + { + if (options == null) + throw new ArgumentNullException("options"); + this.TabSize = options.IndentationSize; + } + + /// + /// The amount of spaces a tab gets converted to. + /// + public int TabSize { get; set; } + + /// + /// Writes the HTML attribute for the style to the text writer. + /// + public virtual void WriteStyleAttributeForColor(TextWriter writer, HighlightingColor color) + { + if (writer == null) + throw new ArgumentNullException("writer"); + if (color == null) + throw new ArgumentNullException("color"); + writer.Write(" style=\""); + writer.Write(color.ToCss()); + writer.Write("\""); + } + + /// + /// Gets whether the color needs to be written out to HTML. + /// + public virtual bool ColorNeedsSpanForStyling(HighlightingColor color) + { + if (color == null) + throw new ArgumentNullException("color"); + return !string.IsNullOrEmpty(color.ToCss()); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlighter.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlighter.cs new file mode 100644 index 000000000..1b5cab138 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlighter.cs @@ -0,0 +1,35 @@ +// 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 Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// Represents a highlighted document. + /// + /// This interface is used by the to register the highlighter as a TextView service. + public interface IHighlighter + { + /// + /// Gets the underlying text document. + /// + TextDocument Document { get; } + + /// + /// Gets the span stack at the end of the specified line. + /// -> GetSpanStack(1) returns the spans at the start of the second line. + /// + /// GetSpanStack(0) is valid and will always return the empty stack. + ImmutableStack GetSpanStack(int lineNumber); + + /// + /// Highlights the specified document line. + /// + /// The line to highlight. + /// A line object that represents the highlighted sections. + HighlightedLine HighlightLine(int lineNumber); + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlightingDefinition.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlightingDefinition.cs new file mode 100644 index 000000000..0b42cd426 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlightingDefinition.cs @@ -0,0 +1,54 @@ +// 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.ComponentModel; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// A highlighting definition. + /// + [TypeConverter(typeof(HighlightingDefinitionTypeConverter))] + public interface IHighlightingDefinition + { + /// + /// Gets the name of the highlighting definition. + /// + string Name { get; } + + /// + /// Gets the main rule set. + /// + HighlightingRuleSet MainRuleSet { get; } + + /// + /// Gets a rule set by name. + /// + /// The rule set, or null if it is not found. + HighlightingRuleSet GetNamedRuleSet(string name); + + /// + /// Gets a named highlighting color. + /// + /// The highlighting color, or null if it is not found. + HighlightingColor GetNamedColor(string name); + + /// + /// Gets the list of named highlighting colors. + /// + IEnumerable NamedHighlightingColors { get; } + } + + /// + /// Extension of IHighlightingDefinition to avoid breaking changes in the API. + /// + public interface IHighlightingDefinition2 : IHighlightingDefinition + { + /// + /// Gets the list of properties. + /// + IDictionary Properties { get; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlightingDefinitionReferenceResolver.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlightingDefinitionReferenceResolver.cs new file mode 100644 index 000000000..d378ae1b7 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/IHighlightingDefinitionReferenceResolver.cs @@ -0,0 +1,18 @@ +// 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; + +namespace Tango.Scripting.Editors.Highlighting +{ + /// + /// Interface for resolvers that can solve cross-definition references. + /// + public interface IHighlightingDefinitionReferenceResolver + { + /// + /// Gets the highlighting definition by name, or null if it is not found. + /// + IHighlightingDefinition GetDefinition(string name); + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs new file mode 100644 index 000000000..a05d1fc75 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; +using Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Rendering; + +namespace Tango.Scripting.Editors.Highlighting +{ + public class OffsetColorizer : DocumentColorizingTransformer + { + public int StartOffset { get; set; } + public int EndOffset { get; set; } + public Brush Brush { get; set; } + public DocumentLine Line { get; set; } + + public OffsetColorizer(DocumentLine line, int start, int end, Brush brush) + { + Line = line; + StartOffset = start; + EndOffset = end; + Brush = brush; + } + + protected override void ColorizeLine(DocumentLine line) + { + if (Line == line) + { + try + { + ChangeLinePart(StartOffset, EndOffset, element => element.TextRunProperties.SetForegroundBrush(Brush)); + } + catch { } + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ASPX.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ASPX.xshd new file mode 100644 index 000000000..bd0c922ac --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ASPX.xshd @@ -0,0 +1,16 @@ + + + + + + + + <% + %> + + + + + + + diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Boo.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Boo.xshd new file mode 100644 index 000000000..a4e555198 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Boo.xshd @@ -0,0 +1,212 @@ + + + + + + + """ + """ + + + \# + + + // + + + /\* + \*/ + + + " + " + + + + + \$\{ + } + + + + + ' + ' + + + + + + @/ + / + + + + /\S+/ + + + + self + super + + + is + isa + and + or + not + + + else + elif + if + match + case + unless + otherwise + for + in + while + + + break + continue + return + yield + goto + + + try + raise + ensure + except + retry + success + + + fixed + unsafe + + + bool + double + single + byte + sbyte + short + ushort + int + uint + long + ulong + date + timespan + decimal + char + object + duck + string + regex + + + void + + + cast + as + + + override + static + virtual + abstract + final + transient + partial + + + public + protected + private + internal + + + namespace + import + from + + + get + set + + + null + value + true + false + ast + + + using + unchecked + checked + lock + getter + required + rawArrayIndexing + normalArrayIndexing + yieldAll + + + assert + array + matrix + print + gets + prompt + enumerate + zip + filter + map + cat + __eval__ + __switch__ + + + constructor + destructor + def + include + event + ref + + + pass + + + enum + class + struct + interface + mixin + callable + do + of + + [\d\w_]+(?=(\s*\()) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + + /\* + \*/ + + + /\* + \*/ + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CPP-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CPP-Mode.xshd new file mode 100644 index 000000000..f552ad413 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CPP-Mode.xshd @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + [?,.;()\[\]{}+\-/%*<>^=~!&]+ + + + __abstract + __box + __delegate + __gc + __identifier + __nogc + __pin + __property + __sealed + __try_cast + __typeof + __value + __event + __hook + __raise + __unhook + __interface + ref class + ref struct + value class + value struct + interface class + interface struct + enum class + enum struct + delegate + event + property + abstract + override + sealed + generic + where + finally + for each + gcnew + in + initonly + literal + nullptr + + + this + + + and + and_eq + bitand + bitor + new + not + not_eq + or + or_eq + xor + xor_eq + + + using + namespace + + + friend + + + private + protected + public + const + volatile + static + + + bool + char + unsigned + union + virtual + double + float + short + signed + void + class + enum + struct + + + false + true + + + do + for + while + + + break + continue + goto + return + + + catch + throw + try + + + case + else + if + switch + default + + + asm + auto + compl + mutable + const_cast + delete + dynamic_cast + explicit + export + extern + inline + int + long + operator + register + reinterpret_cast + sizeof + static_cast + template + typedef + typeid + typename + + + \# + + + // + + + /\* + \*/ + + + " + " + + + + + + ' + ' + + + + + [\d\w_]+(?=(\s*\()) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSS-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSS-Mode.xshd new file mode 100644 index 000000000..3ef562f0d --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSS-Mode.xshd @@ -0,0 +1,57 @@ + + + + + + + + + + + + + /\* + \*/ + + + \{ + \} + + + \# + \s + + [\d\w] + + + + + /\* + \*/ + + + \: + \;|(?=\}) + + + " + " + + + + + + ' + ' + + + + + + + + + diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd new file mode 100644 index 000000000..40f362e08 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd @@ -0,0 +1,311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + + + + \# + + + + (define|undef|if|elif|else|endif|line)\b + + + + // + + + + + + (region|endregion|error|warning|pragma)\b + + + + + + + + + // + + + + /\* + \*/ + + + + " + " + + + + + + + + ' + ' + + + + + + + + @" + " + + + + + + + + + @[\w\d_]+ + + + + include + import + + + + this + base + + + + as + is + new + sizeof + typeof + stackalloc + + + + true + false + + + + else + if + switch + case + default + do + for + foreach + in + while + lock + + + + break + continue + goto + return + + + + yield + partial + class + global + where + select + group + by + into + from + ascending + descending + orderby + let + join + on + equals + var + dynamic + await + void + interface + this + + + + try + throw + catch + finally + + + + checked + unchecked + + + + fixed + unsafe + + + + bool + byte + char + decimal + double + enum + float + int + string + long + sbyte + short + struct + uint + ushort + ulong + null + + + + @ReferenceTypes@ + + + + @InterfaceTypes@ + + + + explicit + implicit + operator + + + + params + ref + out + + + + abstract + const + event + extern + override + readonly + sealed + static + virtual + volatile + async + + + + public + protected + private + internal + + + + namespace + using + + + + get + set + add + remove + + + + null + value + + + + + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + + + diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Coco-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Coco-Mode.xshd new file mode 100644 index 000000000..9395198b5 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Coco-Mode.xshd @@ -0,0 +1,74 @@ + + + + + + + + + + + [{}\(\)\[\]|+\-=\.]+ + + + ANY + CHARACTERS + COMMENTS + COMPILER + CONTEXT + END + FROM + IF + IGNORE + NAMESPACE + NESTED + PRAGMAS + PRODUCTIONS + SYNC + TO + TOKENS + TOKENNAMES + WEAK + using + + + // + + + /\* + \*/ + + + COMPILER + TOKENNAMES + + + " + " + + + ' + ' + + + < + > + + + \(\. + \.\) + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/HTML-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/HTML-Mode.xshd new file mode 100644 index 000000000..fd8211fe4 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/HTML-Mode.xshd @@ -0,0 +1,388 @@ + + + + + + + + + + + + + + + + + + + + + + + <!-- + --> + + + <script\ lang="JavaScript"> + </script> + + + <script\s.*?text/javascript.*?> + </script> + + + <script\ lang="JScript"> + </script> + + + <script\ lang="VBScript"> + </script> + + + <script> + </script> + + + <script[^\w\d_] + </script> + + + < + > + + + & + ; + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + aacute + agrave + acirc + amp + atilde + aring + auml + aelig + ccedil + copy + eacute + egrave + ecirc + euml + iacute + igrave + icirc + iuml + eth + gt + lt + nbsp + ntilde + oacute + ograve + ocirc + otilde + ouml + oslash + quot + reg + szlig + uacute + ugrave + ucirc + uuml + yacute + thorn + trade + yuml + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + / + + + = + + + !DOCTYPE + A + ABBR + ACRONYM + ADDRESS + APPLET + AREA + B + BASE + BASEFONT + BGSOUND + BDO + BIG + BLINK + BLOCKQUOTE + BODY + BR + BUTTON + CAPTION + CENTER + CITE + CODE + COL + COLGROUP + COMMENT + DD + DEL + DFN + DIR + DIV + DL + DT + EM + EMBED + FIELDSET + FONT + FORM + FRAME + FRAMESET + H + H1 + H2 + H3 + H4 + H5 + H6 + HEAD + HR + HTA:APPLICATION + HTML + I + IFRAME + IMG + INPUT + INS + ISINDEX + KBD + LABEL + LEGEnd + LI + LINK + LISTING + MAP + MARQUEE + MENU + META + MULTICOL + NEXTID + NOBR + NOFRAMES + NOSCRIPT + OBJECT + OL + OPTGROUP + OPTION + P + PARAM + PLAINTEXT + PRE + Q + S + SAMP + SCRIPT + SELECT + SERVER + SMALL + SOUND + SPACER + Span + STRONG + STYLE + SUB + SUP + TABLE + TBODY + TD + TEXTAREA + TEXTFLOW + TFOOT + TH + THEAD + TITLE + TR + TT + U + VAR + WBR + XMP + + + abbr + accept-charset + accept + accesskey + action + align + alink + alt + applicationname + archive + axis + background + behavior + bgcolor + bgproperties + border + bordercolor + bordercolordark + bordercolorligh + borderstyle + caption + cellpadding + cellspacing + char + charoff + charset + checked + cite + class + classid + clear + code + codetype + color + cols + colspan + compact + content + coords + data + datetime + declare + defer + dir + direction + disabled + dynsrc + enctype + face + for + frame + frameborder + framespacing + gutter + headers + height + href + hreflang + hspace + http-equiv + icon + id + ismap + label + language + leftmargin + link + longdesc + loop + lowsrc + marginheight + marginwidth + maximizebutton + maxlength + media + method + methods + minimizebutton + multiple + name + nohref + noresize + noshade + nowrap + object + onabort + onblur + onchange + onclick + ondblclick + onerror + onfocus + onkeydown + onkeypress + onkeyup + onload + onmousedown + onmousemove + onmouseout + onmouseover + onmouseup + onreset + onselect + onsubmit + onunload + profile + prompt + readonly + rel + rev + rows + rowspan + rules + runat + scheme + scope + scrollamount + scrolldelay + scrolling + selected + shape + showintaskbar + singleinstance + size + span + src + standby + start + style + summary + sysmenu + tabindex + target + text + title + topmargin + type + urn + usemap + valign + value + valuetype + version + vlink + vrml + vspace + width + windowstate + wrap + + + " + " + + + ' + ' + + [\d\w_]+(?=(\s*=)) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Java-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Java-Mode.xshd new file mode 100644 index 000000000..dd5053e91 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Java-Mode.xshd @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + [?,.()\[\]{}+\-/%*<>^!|]+ + + + this + super + + + new + instanceof + true + false + + + else + if + switch + case + + + do + for + while + + + break + continue + default + goto + return + + + try + throw + catch + finally + + + boolean + double + int + short + long + float + byte + char + + + class + interface + object + + + void + + + abstract + const + static + final + native + extends + implements + volatile + transient + throws + strictfp + synchronized + + + public + protected + private + + + package + import + + + null + + + // + + + /\* + \*/ + + + " + " + + + + + + ' + ' + + + + + [\d\w_]+(?=(\s*\()) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + TODO + + + @author + @version + @param + @return + @exception + @throws + @see + @since + @serial + @serialField + @serialData + @deprecated + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/JavaScript-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/JavaScript-Mode.xshd new file mode 100644 index 000000000..97775dce5 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/JavaScript-Mode.xshd @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + break + continue + delete + else + for + function + if + in + new + return + this + typeof + var + void + while + with + abstract + boolean + byte + case + catch + char + class + const + debugger + default + do + double + enum + export + extends + final + finally + float + goto + implements + import + instanceof + int + interface + long + native + package + private + protected + public + short + static + super + switch + synchronized + throw + throws + transient + try + volatile + + + Array + Boolean + Date + Function + Global + Math + Number + Object + RegExp + String + + + false + null + true + NaN + Infinity + + + eval + parseInt + parseFloat + escape + unescape + isNaN + isFinite + + + // + + + /\* + \*/ + + + + / + / + + + + + + " + " + + + + + + ' + ' + + + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd new file mode 100644 index 000000000..ead5045ab --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + ^\#.* + + + \*\*.*\*\* + + + __.*__ + + + \*(?![ ]).*\* + + + _.*_ + + + `.*` + + + ^\t + ^(?!\t) + + + ^[ ]{4} + ^(?![ ]{4}) + + + ^> + ^(?!>) + + + \!\[.*\]\[.*\] + + + \[.*\]\(.*\) + + + \[.*\]\[.*\] + + + [ ]{2}$ + + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ModeV1.xsd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ModeV1.xsd new file mode 100644 index 000000000..82bce451d --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ModeV1.xsd @@ -0,0 +1,296 @@ + + + + + This schema defines the syntax for mode definitions in SharpDevelop. + The schema can be simplified quite a bit but it does the job as is. + + + If you are using this file as a reference it is probably easiest to scroll to + the botton to find the definition of the root element called SyntaxDefinition and + then unwind the different type definitions and refernces. + + Note on coloring: + Many tags define how some symbol should be colored. If a specific symbol + can not be matched onto either a Span definition, Keyword, or a Digit/Number it + will be rendered in the current default color. Which is the default color of the + current span or the default color of the mode as a whole if no span has been entered. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ModeV2.xsd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ModeV2.xsd new file mode 100644 index 000000000..047ef38a1 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/ModeV2.xsd @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/PHP-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/PHP-Mode.xshd new file mode 100644 index 000000000..f09ff27d9 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/PHP-Mode.xshd @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + \# + + + + // + + + + /\* + \*/ + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | + \b0[0-9]+ # octal number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + + [?,.:;()\[\]{}+\-/%*<>&^!|~@]+ + + + + + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + + + + ' + ' + + + + + + + + " + " + + + + + + + + + <<<\"?[\d\w_]+\"?$ + ^[\d\w_]+; + + + + + <<<\'[\d\w_]+\'$ + ^[\d\w_]+; + + + + global + my + var + + + + and + or + new + clone + instanceof + xor + true + false + + + + else + else + switch + case + endif + elseif + + + + do + for + foreach + while + endwhile + exit + + + + break + continue + default + goto + return + + + + require + include + require + include + function + + + + int + integer + real + double + float + string + array + object + + + + class + void + + + + public + private + + + diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Patch-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Patch-Mode.xshd new file mode 100644 index 000000000..c8e1c3cfd --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Patch-Mode.xshd @@ -0,0 +1,35 @@ + + + + + + + + + + + Index:\s + + + == + + + --- + + + \+\+\+ + + + @@ + + + - + + + \+ + + + \s + + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/PowerShell.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/PowerShell.xshd new file mode 100644 index 000000000..ee6fec4c8 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/PowerShell.xshd @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + \# + + + + <\# + \#> + + + + " + " + + + + + + + + ' + ' + + + + + + + + @" + "@ + + + + + + + + while + param + end + define + else + from + foreach + var + dynamicparam + filter + dp + until + for + exit + switch + process + begin + elseif + if + in + data + class + using + function + + + + catch + finally + throw + trap + try + + + + break + continue + return + + + + class + + + + -not + -band + -bor + -replace + -ireplace + -creplace + -and + -or + -is + -isnot + -as + -lt + -le + -gt + -ge + -eq + -ne + -contains + -notcontains + -like + -notlike + -match + -notmatch + + + + \$[\d\w_]+ + + + + [\w]+-[\w]+ + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Resources.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Resources.cs new file mode 100644 index 000000000..3ac838ce3 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Resources.cs @@ -0,0 +1,48 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.IO; + +namespace Tango.Scripting.Editors.Highlighting +{ + static class Resources + { + static readonly string Prefix = typeof(Resources).FullName + "."; + + public static Stream OpenStream(string name) + { + Stream s = typeof(Resources).Assembly.GetManifestResourceStream(Prefix + name); + if (s == null) + throw new FileNotFoundException("The resource file '" + name + "' was not found."); + return s; + } + + internal static void RegisterBuiltInHighlightings(HighlightingManager.DefaultHighlightingManager hlm) + { + hlm.RegisterHighlighting("XmlDoc", null, "XmlDoc.xshd"); + hlm.RegisterHighlighting("C#", new[] { ".cs" }, "CSharp-Mode.xshd"); + + hlm.RegisterHighlighting("JavaScript", new[] { ".js" }, "JavaScript-Mode.xshd"); + hlm.RegisterHighlighting("HTML", new[] { ".htm", ".html" }, "HTML-Mode.xshd"); + hlm.RegisterHighlighting("ASP/XHTML", new[] { ".asp", ".aspx", ".asax", ".asmx", ".ascx", ".master" }, "ASPX.xshd"); + + hlm.RegisterHighlighting("Boo", new[] { ".boo" }, "Boo.xshd"); + hlm.RegisterHighlighting("Coco", new[] { ".atg" }, "Coco-Mode.xshd"); + hlm.RegisterHighlighting("CSS", new[] { ".css" }, "CSS-Mode.xshd"); + hlm.RegisterHighlighting("C++", new[] { ".c", ".h", ".cc", ".cpp" , ".hpp" }, "CPP-Mode.xshd"); + hlm.RegisterHighlighting("Java", new[] { ".java" }, "Java-Mode.xshd"); + hlm.RegisterHighlighting("Patch", new[] { ".patch", ".diff" }, "Patch-Mode.xshd"); + hlm.RegisterHighlighting("PowerShell", new[] { ".ps1", ".psm1", ".psd1" }, "PowerShell.xshd"); + hlm.RegisterHighlighting("PHP", new[] { ".php" }, "PHP-Mode.xshd"); + hlm.RegisterHighlighting("TeX", new[] { ".tex" }, "Tex-Mode.xshd"); + hlm.RegisterHighlighting("VBNET", new[] { ".vb" }, "VBNET-Mode.xshd"); + hlm.RegisterHighlighting("XML", (".xml;.xsl;.xslt;.xsd;.manifest;.config;.addin;" + + ".xshd;.wxs;.wxi;.wxl;.proj;.csproj;.vbproj;.ilproj;" + + ".booproj;.build;.xfrm;.targets;.xaml;.xpt;" + + ".xft;.map;.wsdl;.disco;.ps1xml;.nuspec").Split(';'), + "XML-Mode.xshd"); + hlm.RegisterHighlighting("MarkDown", new[] { ".md" }, "MarkDown-Mode.xshd"); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Tex-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Tex-Mode.xshd new file mode 100644 index 000000000..91083b0ab --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/Tex-Mode.xshd @@ -0,0 +1,108 @@ + + + + + + + + + + &~!@%^*()-+=|\#/{}[]:;"'<> , .? + + + % + + + + $$ + $$ + + + \[ + \] + + + + \ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &~!@%^*()-+=|\#/{}[]:;"'<> , .? + + + + % + + + + \ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/VBNET-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/VBNET-Mode.xshd new file mode 100644 index 000000000..b22555a29 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/VBNET-Mode.xshd @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + " + " + + + + + + (?<=(^\s*))\# + + + (?<!(^\s*))\# + \# + + + ''' + + + ' + + + \bREM\b + + + Boolean + Byte + Char + Date + Decimal + Double + Integer + Long + Object + SByte + Short + Single + String + UInteger + ULong + UShort + Variant + + + AddressOf + And + AndAlso + Await + Is + IsNot + Like + Mod + New + Not + Or + OrElse + Xor + + + False + Me + MyBase + MyClass + Nothing + True + + + CBool + CByte + CChar + CDate + CDbl + CDec + CInt + CLng + CObj + CSByte + CShort + CSng + CStr + CType + CUInt + CULng + CUShort + DirectCast + GetType + GetXmlNamespace + IIf + TryCast + TypeOf + + + AddHandler + Alias + As + ByRef + ByVal + Call + Case + Catch + Class + Const + Continue + Declare + Default + Delegate + Dim + Do + Each + Else + ElseIf + End + EndIf + Enum + Erase + Error + Event + Exit + Finally + For + Friend + Function + Get + Global + GoSub + GoTo + Handles + If + Implements + Imports + In + Inherits + Interface + Let + Lib + Loop + Module + MustInherit + MustOverride + Namespace + Narrowing + New + Next + NotInheritable + NotOverridable + Of + On + Operator + Option + Optional + Overloads + Overridable + Overrides + ParamArray + Partial + Private + Property + Protected + Public + RaiseEvent + ReadOnly + ReDim + RemoveHandler + Resume + Return + Select + Set + Shadows + Shared + Static + Step + Stop + Structure + Sub + SyncLock + Then + Throw + To + Try + Using + Wend + When + While + Widening + With + WithEvents + WriteOnly + + + Aggregate + Ansi + Ascending + Async + Auto + Binary + By + Compare + Custom + Descending + Distinct + Equals + Explicit + From + Group + Infer + Into + Iterator + Join + Key + Off + Preserve + Skip + Strict + Take + Text + Unicode + Until + Where + Yield + + + + + Const + Else + ElseIf + End + ExternalChecksum + ExternalSource + If + Region + + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd new file mode 100644 index 000000000..8f0bdef76 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + <!-- + --> + + + <!\[CDATA\[ + ]]> + + + <!DOCTYPE + > + + + <\? + \?> + + + < + > + + + + " + "|(?=<) + + + ' + '|(?=<) + + [\d\w_\-\.]+(?=(\s*=)) + = + + + + + + + + & + [\w\d\#]+ + ; + + + + & + [\w\d\#]* + #missing ; + + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XmlDoc.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XmlDoc.xshd new file mode 100644 index 000000000..e4303de6a --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XmlDoc.xshd @@ -0,0 +1,57 @@ + + + + + + + + + + < + > + + + " + " + + + / + | + = + + + c + code + example + exception + list + para + param + paramref + permission + remarks + returns + see + seealso + summary + value + + type + name + cref + item + term + description + listheader + typeparam + typeparamref + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/HighlightingLoader.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/HighlightingLoader.cs new file mode 100644 index 000000000..f1d0d8554 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/HighlightingLoader.cs @@ -0,0 +1,99 @@ +// 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.Xml; +using System.Xml.Schema; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// Static class with helper methods to load XSHD highlighting files. + /// + public static class HighlightingLoader + { + #region XSHD loading + /// + /// Lodas a syntax definition from the xml reader. + /// + public static XshdSyntaxDefinition LoadXshd(XmlReader reader) + { + return LoadXshd(reader, false); + } + + internal static XshdSyntaxDefinition LoadXshd(XmlReader reader, bool skipValidation) + { + if (reader == null) + throw new ArgumentNullException("reader"); + try { + reader.MoveToContent(); + if (reader.NamespaceURI == V2Loader.Namespace) { + return V2Loader.LoadDefinition(reader, skipValidation); + } else { + return V1Loader.LoadDefinition(reader, skipValidation); + } + } catch (XmlSchemaException ex) { + throw WrapException(ex, ex.LineNumber, ex.LinePosition); + } catch (XmlException ex) { + throw WrapException(ex, ex.LineNumber, ex.LinePosition); + } + } + + static Exception WrapException(Exception ex, int lineNumber, int linePosition) + { + return new HighlightingDefinitionInvalidException(FormatExceptionMessage(ex.Message, lineNumber, linePosition), ex); + } + + internal static string FormatExceptionMessage(string message, int lineNumber, int linePosition) + { + if (lineNumber <= 0) + return message; + else + return "Error at position (line " + lineNumber + ", column " + linePosition + "):\n" + message; + } + + internal static XmlReader GetValidatingReader(XmlReader input, bool ignoreWhitespace, XmlSchemaSet schemaSet) + { + XmlReaderSettings settings = new XmlReaderSettings(); + settings.CloseInput = true; + settings.IgnoreComments = true; + settings.IgnoreWhitespace = ignoreWhitespace; + if (schemaSet != null) { + settings.Schemas = schemaSet; + settings.ValidationType = ValidationType.Schema; + } + return XmlReader.Create(input, settings); + } + + internal static XmlSchemaSet LoadSchemaSet(XmlReader schemaInput) + { + XmlSchemaSet schemaSet = new XmlSchemaSet(); + schemaSet.Add(null, schemaInput); + schemaSet.ValidationEventHandler += delegate(object sender, ValidationEventArgs args) { + throw new HighlightingDefinitionInvalidException(args.Message); + }; + return schemaSet; + } + #endregion + + #region Load Highlighting from XSHD + /// + /// Creates a highlighting definition from the XSHD file. + /// + public static IHighlightingDefinition Load(XshdSyntaxDefinition syntaxDefinition, IHighlightingDefinitionReferenceResolver resolver) + { + if (syntaxDefinition == null) + throw new ArgumentNullException("syntaxDefinition"); + return new XmlHighlightingDefinition(syntaxDefinition, resolver); + } + + /// + /// Creates a highlighting definition from the XSHD file. + /// + public static IHighlightingDefinition Load(XmlReader reader, IHighlightingDefinitionReferenceResolver resolver) + { + return Load(LoadXshd(reader), resolver); + } + #endregion + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/IXshdVisitor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/IXshdVisitor.cs new file mode 100644 index 000000000..f328a32d3 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/IXshdVisitor.cs @@ -0,0 +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) + +using System; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// A visitor over the XSHD element tree. + /// + public interface IXshdVisitor + { + /// + object VisitRuleSet(XshdRuleSet ruleSet); + + /// + object VisitColor(XshdColor color); + + /// + object VisitKeywords(XshdKeywords keywords); + + /// + object VisitSpan(XshdSpan span); + + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", Justification = "A VB programmer implementing a visitor?")] + object VisitImport(XshdImport import); + + /// + object VisitRule(XshdRule rule); + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/SaveXshdVisitor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/SaveXshdVisitor.cs new file mode 100644 index 000000000..e158954f1 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/SaveXshdVisitor.cs @@ -0,0 +1,182 @@ +// 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.Linq; +using System.Xml; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// Xshd visitor implementation that saves an .xshd file as XML. + /// + public sealed class SaveXshdVisitor : IXshdVisitor + { + /// + /// XML namespace for XSHD. + /// + public const string Namespace = V2Loader.Namespace; + + XmlWriter writer; + + /// + /// Creates a new SaveXshdVisitor instance. + /// + public SaveXshdVisitor(XmlWriter writer) + { + if (writer == null) + throw new ArgumentNullException("writer"); + this.writer = writer; + } + + /// + /// Writes the specified syntax definition. + /// + public void WriteDefinition(XshdSyntaxDefinition definition) + { + if (definition == null) + throw new ArgumentNullException("definition"); + writer.WriteStartElement("SyntaxDefinition", Namespace); + if (definition.Name != null) + writer.WriteAttributeString("name", definition.Name); + if (definition.Extensions != null) + writer.WriteAttributeString("extensions", string.Join(";", definition.Extensions.ToArray())); + + definition.AcceptElements(this); + + writer.WriteEndElement(); + } + + object IXshdVisitor.VisitRuleSet(XshdRuleSet ruleSet) + { + writer.WriteStartElement("RuleSet", Namespace); + + if (ruleSet.Name != null) + writer.WriteAttributeString("name", ruleSet.Name); + WriteBoolAttribute("ignoreCase", ruleSet.IgnoreCase); + + ruleSet.AcceptElements(this); + + writer.WriteEndElement(); + return null; + } + + void WriteBoolAttribute(string attributeName, bool? value) + { + if (value != null) { + writer.WriteAttributeString(attributeName, value.Value ? "true" : "false"); + } + } + + void WriteRuleSetReference(XshdReference ruleSetReference) + { + if (ruleSetReference.ReferencedElement != null) { + if (ruleSetReference.ReferencedDefinition != null) + writer.WriteAttributeString("ruleSet", ruleSetReference.ReferencedDefinition + "/" + ruleSetReference.ReferencedElement); + else + writer.WriteAttributeString("ruleSet", ruleSetReference.ReferencedElement); + } + } + + void WriteColorReference(XshdReference color) + { + if (color.InlineElement != null) { + WriteColorAttributes(color.InlineElement); + } else if (color.ReferencedElement != null) { + if (color.ReferencedDefinition != null) + writer.WriteAttributeString("color", color.ReferencedDefinition + "/" + color.ReferencedElement); + else + writer.WriteAttributeString("color", color.ReferencedElement); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "The file format requires lowercase, and all possible values are English-only")] + void WriteColorAttributes(XshdColor color) + { + if (color.Foreground != null) + writer.WriteAttributeString("foreground", color.Foreground.ToString()); + if (color.Background != null) + writer.WriteAttributeString("background", color.Background.ToString()); + if (color.FontWeight != null) + writer.WriteAttributeString("fontWeight", V2Loader.FontWeightConverter.ConvertToInvariantString(color.FontWeight.Value).ToLowerInvariant()); + if (color.FontStyle != null) + writer.WriteAttributeString("fontStyle", V2Loader.FontStyleConverter.ConvertToInvariantString(color.FontStyle.Value).ToLowerInvariant()); + } + + object IXshdVisitor.VisitColor(XshdColor color) + { + writer.WriteStartElement("Color", Namespace); + if (color.Name != null) + writer.WriteAttributeString("name", color.Name); + WriteColorAttributes(color); + if (color.ExampleText != null) + writer.WriteAttributeString("exampleText", color.ExampleText); + writer.WriteEndElement(); + return null; + } + + object IXshdVisitor.VisitKeywords(XshdKeywords keywords) + { + writer.WriteStartElement("Keywords", Namespace); + WriteColorReference(keywords.ColorReference); + foreach (string word in keywords.Words) { + writer.WriteElementString("Word", Namespace, word); + } + writer.WriteEndElement(); + return null; + } + + object IXshdVisitor.VisitSpan(XshdSpan span) + { + writer.WriteStartElement("Span", Namespace); + WriteColorReference(span.SpanColorReference); + if (span.BeginRegexType == XshdRegexType.Default && span.BeginRegex != null) + writer.WriteAttributeString("begin", span.BeginRegex); + if (span.EndRegexType == XshdRegexType.Default && span.EndRegex != null) + writer.WriteAttributeString("end", span.EndRegex); + WriteRuleSetReference(span.RuleSetReference); + if (span.Multiline) + writer.WriteAttributeString("multiline", "true"); + + if (span.BeginRegexType == XshdRegexType.IgnorePatternWhitespace) + WriteBeginEndElement("Begin", span.BeginRegex, span.BeginColorReference); + if (span.EndRegexType == XshdRegexType.IgnorePatternWhitespace) + WriteBeginEndElement("End", span.EndRegex, span.EndColorReference); + + if (span.RuleSetReference.InlineElement != null) + span.RuleSetReference.InlineElement.AcceptVisitor(this); + + writer.WriteEndElement(); + return null; + } + + void WriteBeginEndElement(string elementName, string regex, XshdReference colorReference) + { + if (regex != null) { + writer.WriteStartElement(elementName, Namespace); + WriteColorReference(colorReference); + writer.WriteString(regex); + writer.WriteEndElement(); + } + } + + object IXshdVisitor.VisitImport(XshdImport import) + { + writer.WriteStartElement("Import", Namespace); + WriteRuleSetReference(import.RuleSetReference); + writer.WriteEndElement(); + return null; + } + + object IXshdVisitor.VisitRule(XshdRule rule) + { + writer.WriteStartElement("Rule", Namespace); + WriteColorReference(rule.ColorReference); + + writer.WriteString(rule.Regex); + + writer.WriteEndElement(); + return null; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/V1Loader.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/V1Loader.cs new file mode 100644 index 000000000..f3caa7eda --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/V1Loader.cs @@ -0,0 +1,325 @@ +// 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.Globalization; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows; +using System.Windows.Media; +using System.Xml; +using System.Xml.Schema; + +using Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// Loads .xshd files, version 1.0. + /// + sealed class V1Loader + { + static XmlSchemaSet schemaSet; + + static XmlSchemaSet SchemaSet { + get { + if (schemaSet == null) { + schemaSet = HighlightingLoader.LoadSchemaSet(new XmlTextReader( + Resources.OpenStream("ModeV1.xsd"))); + } + return schemaSet; + } + } + + public static XshdSyntaxDefinition LoadDefinition(XmlReader reader, bool skipValidation) + { + reader = HighlightingLoader.GetValidatingReader(reader, false, skipValidation ? null : SchemaSet); + XmlDocument document = new XmlDocument(); + document.Load(reader); + V1Loader loader = new V1Loader(); + return loader.ParseDefinition(document.DocumentElement); + } + + XshdSyntaxDefinition ParseDefinition(XmlElement syntaxDefinition) + { + XshdSyntaxDefinition def = new XshdSyntaxDefinition(); + def.Name = syntaxDefinition.GetAttributeOrNull("name"); + if (syntaxDefinition.HasAttribute("extensions")) { + def.Extensions.AddRange(syntaxDefinition.GetAttribute("extensions").Split(';', '|')); + } + + XshdRuleSet mainRuleSetElement = null; + foreach (XmlElement element in syntaxDefinition.GetElementsByTagName("RuleSet")) { + XshdRuleSet ruleSet = ImportRuleSet(element); + def.Elements.Add(ruleSet); + if (ruleSet.Name == null) + mainRuleSetElement = ruleSet; + + if (syntaxDefinition["Digits"] != null) { + // create digit highlighting rule + + const string optionalExponent = @"([eE][+-]?[0-9]+)?"; + const string floatingPoint = @"\.[0-9]+"; + ruleSet.Elements.Add( + new XshdRule { + ColorReference = GetColorReference(syntaxDefinition["Digits"]), + RegexType = XshdRegexType.IgnorePatternWhitespace, + Regex = @"\b0[xX][0-9a-fA-F]+" + + @"|" + + @"(\b\d+(" + floatingPoint + ")?" + + @"|" + floatingPoint + ")" + + optionalExponent + }); + } + } + + if (syntaxDefinition.HasAttribute("extends") && mainRuleSetElement != null) { + // convert 'extends="HTML"' to '' in main rule set. + mainRuleSetElement.Elements.Add( + new XshdImport { RuleSetReference = new XshdReference( + syntaxDefinition.GetAttribute("extends"), string.Empty + ) }); + } + return def; + } + + static XshdColor GetColorFromElement(XmlElement element) + { + if (!element.HasAttribute("bold") && !element.HasAttribute("italic") && !element.HasAttribute("color") && !element.HasAttribute("bgcolor")) + return null; + XshdColor color = new XshdColor(); + if (element.HasAttribute("bold")) + color.FontWeight = XmlConvert.ToBoolean(element.GetAttribute("bold")) ? FontWeights.Bold : FontWeights.Normal; + if (element.HasAttribute("italic")) + color.FontStyle = XmlConvert.ToBoolean(element.GetAttribute("italic")) ? FontStyles.Italic : FontStyles.Normal; + if (element.HasAttribute("color")) + color.Foreground = ParseColor(element.GetAttribute("color")); + if (element.HasAttribute("bgcolor")) + color.Background = ParseColor(element.GetAttribute("bgcolor")); + return color; + } + + static XshdReference GetColorReference(XmlElement element) + { + XshdColor color = GetColorFromElement(element); + if (color != null) + return new XshdReference(color); + else + return new XshdReference(); + } + + static HighlightingBrush ParseColor(string c) + { + if (c.StartsWith("#", StringComparison.Ordinal)) { + int a = 255; + int offset = 0; + if (c.Length > 7) { + offset = 2; + a = Int32.Parse(c.Substring(1,2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + + int r = Int32.Parse(c.Substring(1 + offset,2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); + int g = Int32.Parse(c.Substring(3 + offset,2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); + int b = Int32.Parse(c.Substring(5 + offset,2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); + return new SimpleHighlightingBrush(Color.FromArgb((byte)a, (byte)r, (byte)g, (byte)b)); + } else if (c.StartsWith("SystemColors.", StringComparison.Ordinal)) { + return V2Loader.GetSystemColorBrush(null, c); + } else { + return new SimpleHighlightingBrush((Color)V2Loader.ColorConverter.ConvertFromInvariantString(c)); + } + } + + char ruleSetEscapeCharacter; + + XshdRuleSet ImportRuleSet(XmlElement element) + { + XshdRuleSet ruleSet = new XshdRuleSet(); + ruleSet.Name = element.GetAttributeOrNull("name"); + + if (element.HasAttribute("escapecharacter")) { + ruleSetEscapeCharacter = element.GetAttribute("escapecharacter")[0]; + } else { + ruleSetEscapeCharacter = '\0'; + } + + if (element.HasAttribute("reference")) { + ruleSet.Elements.Add( + new XshdImport { RuleSetReference = new XshdReference( + element.GetAttribute("reference"), string.Empty + ) }); + } + ruleSet.IgnoreCase = element.GetBoolAttribute("ignorecase"); + + foreach (XmlElement el in element.GetElementsByTagName("KeyWords")) { + XshdKeywords keywords = new XshdKeywords(); + keywords.ColorReference = GetColorReference(el); + // we have to handle old syntax highlighting definitions that contain + // empty keywords or empty keyword groups + foreach (XmlElement node in el.GetElementsByTagName("Key")) { + string word = node.GetAttribute("word"); + if (!string.IsNullOrEmpty(word)) + keywords.Words.Add(word); + } + if (keywords.Words.Count > 0) { + ruleSet.Elements.Add(keywords); + } + } + + foreach (XmlElement el in element.GetElementsByTagName("Span")) { + ruleSet.Elements.Add(ImportSpan(el)); + } + + foreach (XmlElement el in element.GetElementsByTagName("MarkPrevious")) { + ruleSet.Elements.Add(ImportMarkPrevNext(el, false)); + } + foreach (XmlElement el in element.GetElementsByTagName("MarkFollowing")) { + ruleSet.Elements.Add(ImportMarkPrevNext(el, true)); + } + + return ruleSet; + } + + static XshdRule ImportMarkPrevNext(XmlElement el, bool markFollowing) + { + bool markMarker = el.GetBoolAttribute("markmarker") ?? false; + string what = Regex.Escape(el.InnerText); + const string identifier = @"[\d\w_]+"; + const string whitespace = @"\s*"; + + string regex; + if (markFollowing) { + if (markMarker) { + regex = what + whitespace + identifier; + } else { + regex = "(?<=(" + what + whitespace + "))" + identifier; + } + } else { + if (markMarker) { + regex = identifier + whitespace + what; + } else { + regex = identifier + "(?=(" + whitespace + what + "))"; + } + } + return new XshdRule { + ColorReference = GetColorReference(el), + Regex = regex, + RegexType = XshdRegexType.IgnorePatternWhitespace + }; + } + + XshdSpan ImportSpan(XmlElement element) + { + XshdSpan span = new XshdSpan(); + if (element.HasAttribute("rule")) { + span.RuleSetReference = new XshdReference(null, element.GetAttribute("rule")); + } + char escapeCharacter = ruleSetEscapeCharacter; + if (element.HasAttribute("escapecharacter")) { + escapeCharacter = element.GetAttribute("escapecharacter")[0]; + } + span.Multiline = !(element.GetBoolAttribute("stopateol") ?? false); + + span.SpanColorReference = GetColorReference(element); + + span.BeginRegexType = XshdRegexType.IgnorePatternWhitespace; + span.BeginRegex = ImportRegex(element["Begin"].InnerText, + element["Begin"].GetBoolAttribute("singleword") ?? false, + element["Begin"].GetBoolAttribute("startofline")); + span.BeginColorReference = GetColorReference(element["Begin"]); + + string endElementText = string.Empty; + if (element["End"] != null) { + span.EndRegexType = XshdRegexType.IgnorePatternWhitespace; + endElementText = element["End"].InnerText; + span.EndRegex = ImportRegex(endElementText, + element["End"].GetBoolAttribute("singleword") ?? false, + null); + span.EndColorReference = GetColorReference(element["End"]); + } + + if (escapeCharacter != '\0') { + XshdRuleSet ruleSet = new XshdRuleSet(); + if (endElementText.Length == 1 && endElementText[0] == escapeCharacter) { + // ""-style escape + ruleSet.Elements.Add(new XshdSpan { + BeginRegex = Regex.Escape(endElementText + endElementText), + EndRegex = "" + }); + } else { + // \"-style escape + ruleSet.Elements.Add(new XshdSpan { + BeginRegex = Regex.Escape(escapeCharacter.ToString()), + EndRegex = "." + }); + } + if (span.RuleSetReference.ReferencedElement != null) { + ruleSet.Elements.Add(new XshdImport { RuleSetReference = span.RuleSetReference }); + } + span.RuleSetReference = new XshdReference(ruleSet); + } + return span; + } + + static string ImportRegex(string expr, bool singleWord, bool? startOfLine) + { + StringBuilder b = new StringBuilder(); + if (startOfLine != null) { + if (startOfLine.Value) { + b.Append(@"(?<=(^\s*))"); + } else { + b.Append(@"(? + /// Loads .xshd files, version 2.0. + /// Version 2.0 files are recognized by the namespace. + /// + static class V2Loader + { + public const string Namespace = "http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008"; + + static XmlSchemaSet schemaSet; + + static XmlSchemaSet SchemaSet { + get { + if (schemaSet == null) { + schemaSet = HighlightingLoader.LoadSchemaSet(new XmlTextReader( + Resources.OpenStream("ModeV2.xsd"))); + } + return schemaSet; + } + } + + public static XshdSyntaxDefinition LoadDefinition(XmlReader reader, bool skipValidation) + { + reader = HighlightingLoader.GetValidatingReader(reader, true, skipValidation ? null : SchemaSet); + reader.Read(); + return ParseDefinition(reader); + } + + static XshdSyntaxDefinition ParseDefinition(XmlReader reader) + { + Debug.Assert(reader.LocalName == "SyntaxDefinition"); + XshdSyntaxDefinition def = new XshdSyntaxDefinition(); + def.Name = reader.GetAttribute("name"); + string extensions = reader.GetAttribute("extensions"); + if (extensions != null) + def.Extensions.AddRange(extensions.Split(';')); + ParseElements(def.Elements, reader); + Debug.Assert(reader.NodeType == XmlNodeType.EndElement); + Debug.Assert(reader.LocalName == "SyntaxDefinition"); + return def; + } + + static void ParseElements(ICollection c, XmlReader reader) + { + if (reader.IsEmptyElement) + return; + while (reader.Read() && reader.NodeType != XmlNodeType.EndElement) { + Debug.Assert(reader.NodeType == XmlNodeType.Element); + if (reader.NamespaceURI != Namespace) { + if (!reader.IsEmptyElement) + reader.Skip(); + continue; + } + switch (reader.Name) { + case "RuleSet": + c.Add(ParseRuleSet(reader)); + break; + case "Property": + c.Add(ParseProperty(reader)); + break; + case "Color": + c.Add(ParseNamedColor(reader)); + break; + case "Keywords": + c.Add(ParseKeywords(reader)); + break; + case "Span": + c.Add(ParseSpan(reader)); + break; + case "Import": + c.Add(ParseImport(reader)); + break; + case "Rule": + c.Add(ParseRule(reader)); + break; + default: + throw new NotSupportedException("Unknown element " + reader.Name); + } + } + } + + static XshdElement ParseProperty(XmlReader reader) + { + XshdProperty property = new XshdProperty(); + SetPosition(property, reader); + property.Name = reader.GetAttribute("name"); + property.Value = reader.GetAttribute("value"); + return property; + } + + static XshdRuleSet ParseRuleSet(XmlReader reader) + { + XshdRuleSet ruleSet = new XshdRuleSet(); + SetPosition(ruleSet, reader); + ruleSet.Name = reader.GetAttribute("name"); + ruleSet.IgnoreCase = reader.GetBoolAttribute("ignoreCase"); + + CheckElementName(reader, ruleSet.Name); + ParseElements(ruleSet.Elements, reader); + return ruleSet; + } + + static XshdRule ParseRule(XmlReader reader) + { + XshdRule rule = new XshdRule(); + SetPosition(rule, reader); + rule.ColorReference = ParseColorReference(reader); + if (!reader.IsEmptyElement) { + reader.Read(); + if (reader.NodeType == XmlNodeType.Text) { + rule.Regex = reader.ReadContentAsString(); + rule.RegexType = XshdRegexType.IgnorePatternWhitespace; + } + } + return rule; + } + + static XshdKeywords ParseKeywords(XmlReader reader) + { + XshdKeywords keywords = new XshdKeywords(); + SetPosition(keywords, reader); + keywords.ColorReference = ParseColorReference(reader); + reader.Read(); + while (reader.NodeType != XmlNodeType.EndElement) { + Debug.Assert(reader.NodeType == XmlNodeType.Element); + keywords.Words.Add(reader.ReadElementString()); + } + return keywords; + } + + static XshdImport ParseImport(XmlReader reader) + { + XshdImport import = new XshdImport(); + SetPosition(import, reader); + import.RuleSetReference = ParseRuleSetReference(reader); + if (!reader.IsEmptyElement) + reader.Skip(); + return import; + } + + static XshdSpan ParseSpan(XmlReader reader) + { + XshdSpan span = new XshdSpan(); + SetPosition(span, reader); + span.BeginRegex = reader.GetAttribute("begin"); + span.EndRegex = reader.GetAttribute("end"); + span.Multiline = reader.GetBoolAttribute("multiline") ?? false; + span.SpanColorReference = ParseColorReference(reader); + span.RuleSetReference = ParseRuleSetReference(reader); + if (!reader.IsEmptyElement) { + reader.Read(); + while (reader.NodeType != XmlNodeType.EndElement) { + Debug.Assert(reader.NodeType == XmlNodeType.Element); + switch (reader.Name) { + case "Begin": + if (span.BeginRegex != null) + throw Error(reader, "Duplicate Begin regex"); + span.BeginColorReference = ParseColorReference(reader); + span.BeginRegex = reader.ReadElementString(); + span.BeginRegexType = XshdRegexType.IgnorePatternWhitespace; + break; + case "End": + if (span.EndRegex != null) + throw Error(reader, "Duplicate End regex"); + span.EndColorReference = ParseColorReference(reader); + span.EndRegex = reader.ReadElementString(); + span.EndRegexType = XshdRegexType.IgnorePatternWhitespace; + break; + case "RuleSet": + if (span.RuleSetReference.ReferencedElement != null) + throw Error(reader, "Cannot specify both inline RuleSet and RuleSet reference"); + span.RuleSetReference = new XshdReference(ParseRuleSet(reader)); + reader.Read(); + break; + default: + throw new NotSupportedException("Unknown element " + reader.Name); + } + } + } + return span; + } + + static Exception Error(XmlReader reader, string message) + { + return Error(reader as IXmlLineInfo, message); + } + + static Exception Error(IXmlLineInfo lineInfo, string message) + { + if (lineInfo != null) + return new HighlightingDefinitionInvalidException(HighlightingLoader.FormatExceptionMessage(message, lineInfo.LineNumber, lineInfo.LinePosition)); + else + return new HighlightingDefinitionInvalidException(message); + } + + /// + /// Sets the element's position to the XmlReader's position. + /// + static void SetPosition(XshdElement element, XmlReader reader) + { + IXmlLineInfo lineInfo = reader as IXmlLineInfo; + if (lineInfo != null) { + element.LineNumber = lineInfo.LineNumber; + element.ColumnNumber = lineInfo.LinePosition; + } + } + + static XshdReference ParseRuleSetReference(XmlReader reader) + { + string ruleSet = reader.GetAttribute("ruleSet"); + if (ruleSet != null) { + // '/' is valid in highlighting definition names, so we need the last occurence + int pos = ruleSet.LastIndexOf('/'); + if (pos >= 0) { + return new XshdReference(ruleSet.Substring(0, pos), ruleSet.Substring(pos + 1)); + } else { + return new XshdReference(null, ruleSet); + } + } else { + return new XshdReference(); + } + } + + static void CheckElementName(XmlReader reader, string name) + { + if (name != null) { + if (name.Length == 0) + throw Error(reader, "The empty string is not a valid name."); + if (name.IndexOf('/') >= 0) + throw Error(reader, "Element names must not contain a slash."); + } + } + + #region ParseColor + static XshdColor ParseNamedColor(XmlReader reader) + { + XshdColor color = ParseColorAttributes(reader); + // check removed: invisible named colors may be useful now that apps can read highlighting data + //if (color.Foreground == null && color.FontWeight == null && color.FontStyle == null) + // throw Error(reader, "A named color must have at least one element."); + color.Name = reader.GetAttribute("name"); + CheckElementName(reader, color.Name); + color.ExampleText = reader.GetAttribute("exampleText"); + return color; + } + + static XshdReference ParseColorReference(XmlReader reader) + { + string color = reader.GetAttribute("color"); + if (color != null) { + int pos = color.LastIndexOf('/'); + if (pos >= 0) { + return new XshdReference(color.Substring(0, pos), color.Substring(pos + 1)); + } else { + return new XshdReference(null, color); + } + } else { + return new XshdReference(ParseColorAttributes(reader)); + } + } + + static XshdColor ParseColorAttributes(XmlReader reader) + { + XshdColor color = new XshdColor(); + SetPosition(color, reader); + IXmlLineInfo position = reader as IXmlLineInfo; + color.Foreground = ParseColor(position, reader.GetAttribute("foreground")); + color.Background = ParseColor(position, reader.GetAttribute("background")); + color.FontWeight = ParseFontWeight(reader.GetAttribute("fontWeight")); + color.FontStyle = ParseFontStyle(reader.GetAttribute("fontStyle")); + return color; + } + + internal readonly static ColorConverter ColorConverter = new ColorConverter(); + internal readonly static FontWeightConverter FontWeightConverter = new FontWeightConverter(); + internal readonly static FontStyleConverter FontStyleConverter = new FontStyleConverter(); + + static HighlightingBrush ParseColor(IXmlLineInfo lineInfo, string color) + { + if (string.IsNullOrEmpty(color)) + return null; + if (color.StartsWith("SystemColors.", StringComparison.Ordinal)) + return GetSystemColorBrush(lineInfo, color); + else + return FixedColorHighlightingBrush((Color?)ColorConverter.ConvertFromInvariantString(color)); + } + + internal static SystemColorHighlightingBrush GetSystemColorBrush(IXmlLineInfo lineInfo, string name) + { + Debug.Assert(name.StartsWith("SystemColors.", StringComparison.Ordinal)); + string shortName = name.Substring(13); + var property = typeof(SystemColors).GetProperty(shortName + "Brush"); + if (property == null) + throw Error(lineInfo, "Cannot find '" + name + "'."); + return new SystemColorHighlightingBrush(property); + } + + static HighlightingBrush FixedColorHighlightingBrush(Color? color) + { + if (color == null) + return null; + return new SimpleHighlightingBrush(color.Value); + } + + static FontWeight? ParseFontWeight(string fontWeight) + { + if (string.IsNullOrEmpty(fontWeight)) + return null; + return (FontWeight?)FontWeightConverter.ConvertFromInvariantString(fontWeight); + } + + static FontStyle? ParseFontStyle(string fontStyle) + { + if (string.IsNullOrEmpty(fontStyle)) + return null; + return (FontStyle?)FontStyleConverter.ConvertFromInvariantString(fontStyle); + } + #endregion + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XmlHighlightingDefinition.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XmlHighlightingDefinition.cs new file mode 100644 index 000000000..3f52e5d87 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XmlHighlightingDefinition.cs @@ -0,0 +1,406 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Text.RegularExpressions; +using Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + [Serializable] + sealed class XmlHighlightingDefinition : IHighlightingDefinition2 + { + public string Name { get; private set; } + + public XmlHighlightingDefinition(XshdSyntaxDefinition xshd, IHighlightingDefinitionReferenceResolver resolver) + { + this.Name = xshd.Name; + // Create HighlightingRuleSet instances + var rnev = new RegisterNamedElementsVisitor(this); + xshd.AcceptElements(rnev); + // Assign MainRuleSet so that references can be resolved + foreach (XshdElement element in xshd.Elements) { + XshdRuleSet xrs = element as XshdRuleSet; + if (xrs != null && xrs.Name == null) { + if (MainRuleSet != null) + throw Error(element, "Duplicate main RuleSet. There must be only one nameless RuleSet!"); + else + MainRuleSet = rnev.ruleSets[xrs]; + } + } + if (MainRuleSet == null) + throw new HighlightingDefinitionInvalidException("Could not find main RuleSet."); + // Translate elements within the rulesets (resolving references and processing imports) + xshd.AcceptElements(new TranslateElementVisitor(this, rnev.ruleSets, resolver)); + + foreach (var p in xshd.Elements.OfType()) + propDict.Add(p.Name, p.Value); + } + + #region RegisterNamedElements + sealed class RegisterNamedElementsVisitor : IXshdVisitor + { + XmlHighlightingDefinition def; + internal readonly Dictionary ruleSets + = new Dictionary(); + + public RegisterNamedElementsVisitor(XmlHighlightingDefinition def) + { + this.def = def; + } + + public object VisitRuleSet(XshdRuleSet ruleSet) + { + HighlightingRuleSet hrs = new HighlightingRuleSet(); + ruleSets.Add(ruleSet, hrs); + if (ruleSet.Name != null) { + if (ruleSet.Name.Length == 0) + throw Error(ruleSet, "Name must not be the empty string"); + if (def.ruleSetDict.ContainsKey(ruleSet.Name)) + throw Error(ruleSet, "Duplicate rule set name '" + ruleSet.Name + "'."); + + def.ruleSetDict.Add(ruleSet.Name, hrs); + } + ruleSet.AcceptElements(this); + return null; + } + + public object VisitColor(XshdColor color) + { + if (color.Name != null) { + if (color.Name.Length == 0) + throw Error(color, "Name must not be the empty string"); + if (def.colorDict.ContainsKey(color.Name)) + throw Error(color, "Duplicate color name '" + color.Name + "'."); + + def.colorDict.Add(color.Name, new HighlightingColor()); + } + return null; + } + + public object VisitKeywords(XshdKeywords keywords) + { + return keywords.ColorReference.AcceptVisitor(this); + } + + public object VisitSpan(XshdSpan span) + { + span.BeginColorReference.AcceptVisitor(this); + span.SpanColorReference.AcceptVisitor(this); + span.EndColorReference.AcceptVisitor(this); + return span.RuleSetReference.AcceptVisitor(this); + } + + public object VisitImport(XshdImport import) + { + return import.RuleSetReference.AcceptVisitor(this); + } + + public object VisitRule(XshdRule rule) + { + return rule.ColorReference.AcceptVisitor(this); + } + } + #endregion + + #region TranslateElements + sealed class TranslateElementVisitor : IXshdVisitor + { + readonly XmlHighlightingDefinition def; + readonly Dictionary ruleSetDict; + readonly Dictionary reverseRuleSetDict; + readonly IHighlightingDefinitionReferenceResolver resolver; + HashSet processingStartedRuleSets = new HashSet(); + HashSet processedRuleSets = new HashSet(); + bool ignoreCase; + + public TranslateElementVisitor(XmlHighlightingDefinition def, Dictionary ruleSetDict, IHighlightingDefinitionReferenceResolver resolver) + { + Debug.Assert(def != null); + Debug.Assert(ruleSetDict != null); + this.def = def; + this.ruleSetDict = ruleSetDict; + this.resolver = resolver; + reverseRuleSetDict = new Dictionary(); + foreach (var pair in ruleSetDict) { + reverseRuleSetDict.Add(pair.Value, pair.Key); + } + } + + public object VisitRuleSet(XshdRuleSet ruleSet) + { + HighlightingRuleSet rs = ruleSetDict[ruleSet]; + if (processedRuleSets.Contains(ruleSet)) + return rs; + if (!processingStartedRuleSets.Add(ruleSet)) + throw Error(ruleSet, "RuleSet cannot be processed because it contains cyclic "); + + bool oldIgnoreCase = ignoreCase; + if (ruleSet.IgnoreCase != null) + ignoreCase = ruleSet.IgnoreCase.Value; + + rs.Name = ruleSet.Name; + + foreach (XshdElement element in ruleSet.Elements) { + object o = element.AcceptVisitor(this); + HighlightingRuleSet elementRuleSet = o as HighlightingRuleSet; + if (elementRuleSet != null) { + Merge(rs, elementRuleSet); + } else { + HighlightingSpan span = o as HighlightingSpan; + if (span != null) { + rs.Spans.Add(span); + } else { + HighlightingRule elementRule = o as HighlightingRule; + if (elementRule != null) { + rs.Rules.Add(elementRule); + } + } + } + } + + ignoreCase = oldIgnoreCase; + processedRuleSets.Add(ruleSet); + + return rs; + } + + static void Merge(HighlightingRuleSet target, HighlightingRuleSet source) + { + target.Rules.AddRange(source.Rules); + target.Spans.AddRange(source.Spans); + } + + public object VisitColor(XshdColor color) + { + HighlightingColor c; + if (color.Name != null) + c = def.colorDict[color.Name]; + else if (color.Foreground == null && color.FontStyle == null && color.FontWeight == null) + return null; + else + c = new HighlightingColor(); + + c.Name = color.Name; + c.Foreground = color.Foreground; + c.Background = color.Background; + c.FontStyle = color.FontStyle; + c.FontWeight = color.FontWeight; + return c; + } + + public object VisitKeywords(XshdKeywords keywords) + { + if (keywords.Words.Count == 0) + return Error(keywords, "Keyword group must not be empty."); + foreach (string keyword in keywords.Words) { + if (string.IsNullOrEmpty(keyword)) + throw Error(keywords, "Cannot use empty string as keyword"); + } + StringBuilder keyWordRegex = new StringBuilder(); + // We can use "\b" only where the keyword starts/ends with a letter or digit, otherwise we don't + // highlight correctly. (example: ILAsm-Mode.xshd with ".maxstack" keyword) + if (keywords.Words.All(IsSimpleWord)) { + keyWordRegex.Append(@"\b(?>"); + // (?> = atomic group + // atomic groups increase matching performance, but we + // must ensure that the keywords are sorted correctly. + // "\b(?>in|int)\b" does not match "int" because the atomic group captures "in". + // To solve this, we are sorting the keywords by descending length. + int i = 0; + foreach (string keyword in keywords.Words.OrderByDescending(w=>w.Length)) { + if (i++ > 0) + keyWordRegex.Append('|'); + keyWordRegex.Append(Regex.Escape(keyword)); + } + keyWordRegex.Append(@")\b"); + } else { + keyWordRegex.Append('('); + int i = 0; + foreach (string keyword in keywords.Words) { + if (i++ > 0) + keyWordRegex.Append('|'); + if (char.IsLetterOrDigit(keyword[0])) + keyWordRegex.Append(@"\b"); + keyWordRegex.Append(Regex.Escape(keyword)); + if (char.IsLetterOrDigit(keyword[keyword.Length - 1])) + keyWordRegex.Append(@"\b"); + } + keyWordRegex.Append(')'); + } + return new HighlightingRule { + Color = GetColor(keywords, keywords.ColorReference), + Regex = CreateRegex(keywords, keyWordRegex.ToString(), XshdRegexType.Default) + }; + } + + static bool IsSimpleWord(string word) + { + return char.IsLetterOrDigit(word[0]) && char.IsLetterOrDigit(word, word.Length - 1); + } + + Regex CreateRegex(XshdElement position, string regex, XshdRegexType regexType) + { + if (regex == null) + throw Error(position, "Regex missing"); + RegexOptions options = RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture; + if (regexType == XshdRegexType.IgnorePatternWhitespace) + options |= RegexOptions.IgnorePatternWhitespace; + if (ignoreCase) + options |= RegexOptions.IgnoreCase; + try { + return new Regex(regex, options); + } catch (ArgumentException ex) { + throw Error(position, ex.Message); + } + } + + HighlightingColor GetColor(XshdElement position, XshdReference colorReference) + { + if (colorReference.InlineElement != null) { + return (HighlightingColor)colorReference.InlineElement.AcceptVisitor(this); + } else if (colorReference.ReferencedElement != null) { + IHighlightingDefinition definition = GetDefinition(position, colorReference.ReferencedDefinition); + HighlightingColor color = definition.GetNamedColor(colorReference.ReferencedElement); + if (color == null) + throw Error(position, "Could not find color named '" + colorReference.ReferencedElement + "'."); + return color; + } else { + return null; + } + } + + IHighlightingDefinition GetDefinition(XshdElement position, string definitionName) + { + if (definitionName == null) + return def; + if (resolver == null) + throw Error(position, "Resolving references to other syntax definitions is not possible because the IHighlightingDefinitionReferenceResolver is null."); + IHighlightingDefinition d = resolver.GetDefinition(definitionName); + if (d == null) + throw Error(position, "Could not find definition with name '" + definitionName + "'."); + return d; + } + + HighlightingRuleSet GetRuleSet(XshdElement position, XshdReference ruleSetReference) + { + if (ruleSetReference.InlineElement != null) { + return (HighlightingRuleSet)ruleSetReference.InlineElement.AcceptVisitor(this); + } else if (ruleSetReference.ReferencedElement != null) { + IHighlightingDefinition definition = GetDefinition(position, ruleSetReference.ReferencedDefinition); + HighlightingRuleSet ruleSet = definition.GetNamedRuleSet(ruleSetReference.ReferencedElement); + if (ruleSet == null) + throw Error(position, "Could not find rule set named '" + ruleSetReference.ReferencedElement + "'."); + return ruleSet; + } else { + return null; + } + } + + public object VisitSpan(XshdSpan span) + { + string endRegex = span.EndRegex; + if (string.IsNullOrEmpty(span.BeginRegex) && string.IsNullOrEmpty(span.EndRegex)) + throw Error(span, "Span has no start/end regex."); + if (!span.Multiline) { + if (endRegex == null) + endRegex = "$"; + else if (span.EndRegexType == XshdRegexType.IgnorePatternWhitespace) + endRegex = "($|" + endRegex + "\n)"; + else + endRegex = "($|" + endRegex + ")"; + } + HighlightingColor wholeSpanColor = GetColor(span, span.SpanColorReference); + return new HighlightingSpan { + StartExpression = CreateRegex(span, span.BeginRegex, span.BeginRegexType), + EndExpression = CreateRegex(span, endRegex, span.EndRegexType), + RuleSet = GetRuleSet(span, span.RuleSetReference), + StartColor = GetColor(span, span.BeginColorReference), + SpanColor = wholeSpanColor, + EndColor = GetColor(span, span.EndColorReference), + SpanColorIncludesStart = true, + SpanColorIncludesEnd = true + }; + } + + public object VisitImport(XshdImport import) + { + HighlightingRuleSet hrs = GetRuleSet(import, import.RuleSetReference); + XshdRuleSet inputRuleSet; + if (reverseRuleSetDict.TryGetValue(hrs, out inputRuleSet)) { + // ensure the ruleset is processed before importing its members + if (VisitRuleSet(inputRuleSet) != hrs) + Debug.Fail("this shouldn't happen"); + } + return hrs; + } + + public object VisitRule(XshdRule rule) + { + return new HighlightingRule { + Color = GetColor(rule, rule.ColorReference), + Regex = CreateRegex(rule, rule.Regex, rule.RegexType) + }; + } + } + #endregion + + static Exception Error(XshdElement element, string message) + { + if (element.LineNumber > 0) + return new HighlightingDefinitionInvalidException( + "Error at line " + element.LineNumber + ":\n" + message); + else + return new HighlightingDefinitionInvalidException(message); + } + + Dictionary ruleSetDict = new Dictionary(); + Dictionary colorDict = new Dictionary(); + [OptionalField] + Dictionary propDict = new Dictionary(); + + public HighlightingRuleSet MainRuleSet { get; private set; } + + public HighlightingRuleSet GetNamedRuleSet(string name) + { + if (string.IsNullOrEmpty(name)) + return MainRuleSet; + HighlightingRuleSet r; + if (ruleSetDict.TryGetValue(name, out r)) + return r; + else + return null; + } + + public HighlightingColor GetNamedColor(string name) + { + HighlightingColor c; + if (colorDict.TryGetValue(name, out c)) + return c; + else + return null; + } + + public IEnumerable NamedHighlightingColors { + get { + return colorDict.Values; + } + } + + public override string ToString() + { + return this.Name; + } + + public IDictionary Properties { + get { + return propDict; + } + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdColor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdColor.cs new file mode 100644 index 000000000..bbc5abb98 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdColor.cs @@ -0,0 +1,97 @@ +// 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.Runtime.Serialization; +using System.Security.Permissions; +using System.Windows; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// A color in an Xshd file. + /// + [Serializable] + public class XshdColor : XshdElement, ISerializable + { + /// + /// Gets/sets the name. + /// + public string Name { get; set; } + + /// + /// Gets/sets the foreground brush. + /// + public HighlightingBrush Foreground { get; set; } + + /// + /// Gets/sets the background brush. + /// + public HighlightingBrush Background { get; set; } + + /// + /// Gets/sets the font weight. + /// + public FontWeight? FontWeight { get; set; } + + /// + /// Gets/sets the font style. + /// + public FontStyle? FontStyle { get; set; } + + /// + /// Gets/Sets the example text that demonstrates where the color is used. + /// + public string ExampleText { get; set; } + + /// + /// Creates a new XshdColor instance. + /// + public XshdColor() + { + } + + /// + /// Deserializes an XshdColor. + /// + protected XshdColor(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + this.Name = info.GetString("Name"); + this.Foreground = (HighlightingBrush)info.GetValue("Foreground", typeof(HighlightingBrush)); + this.Background = (HighlightingBrush)info.GetValue("Background", typeof(HighlightingBrush)); + if (info.GetBoolean("HasWeight")) + this.FontWeight = System.Windows.FontWeight.FromOpenTypeWeight(info.GetInt32("Weight")); + if (info.GetBoolean("HasStyle")) + this.FontStyle = (FontStyle?)new FontStyleConverter().ConvertFromInvariantString(info.GetString("Style")); + this.ExampleText = info.GetString("ExampleText"); + } + + /// + /// Serializes this XshdColor instance. + /// + [System.Security.SecurityCritical] + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + info.AddValue("Name", this.Name); + info.AddValue("Foreground", this.Foreground); + info.AddValue("Background", this.Background); + info.AddValue("HasWeight", this.FontWeight.HasValue); + if (this.FontWeight.HasValue) + info.AddValue("Weight", this.FontWeight.Value.ToOpenTypeWeight()); + info.AddValue("HasStyle", this.FontStyle.HasValue); + if (this.FontStyle.HasValue) + info.AddValue("Style", this.FontStyle.Value.ToString()); + info.AddValue("ExampleText", this.ExampleText); + } + + /// + public override object AcceptVisitor(IXshdVisitor visitor) + { + return visitor.VisitColor(this); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdElement.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdElement.cs new file mode 100644 index 000000000..d7634e63e --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdElement.cs @@ -0,0 +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) + +using System; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// An element in a XSHD rule set. + /// + [Serializable] + public abstract class XshdElement + { + /// + /// Gets the line number in the .xshd file. + /// + public int LineNumber { get; set; } + + /// + /// Gets the column number in the .xshd file. + /// + public int ColumnNumber { get; set; } + + /// + /// Applies the visitor to this element. + /// + public abstract object AcceptVisitor(IXshdVisitor visitor); + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdImport.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdImport.cs new file mode 100644 index 000000000..68ecdd2d0 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdImport.cs @@ -0,0 +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) + +using System; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// <Import> element. + /// + [Serializable] + public class XshdImport : XshdElement + { + /// + /// Gets/sets the referenced rule set. + /// + public XshdReference RuleSetReference { get; set; } + + /// + public override object AcceptVisitor(IXshdVisitor visitor) + { + return visitor.VisitImport(this); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdKeywords.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdKeywords.cs new file mode 100644 index 000000000..245f34ae5 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdKeywords.cs @@ -0,0 +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) + +using System; +using System.Collections.Generic; +using Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// A list of keywords. + /// + [Serializable] + public class XshdKeywords : XshdElement + { + /// + /// The color. + /// + public XshdReference ColorReference { get; set; } + + readonly NullSafeCollection words = new NullSafeCollection(); + + /// + /// Gets the list of key words. + /// + public IList Words { + get { return words; } + } + + /// + public override object AcceptVisitor(IXshdVisitor visitor) + { + return visitor.VisitKeywords(this); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdProperty.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdProperty.cs new file mode 100644 index 000000000..3ca65f4b4 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdProperty.cs @@ -0,0 +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) + +using System; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// A property in an Xshd file. + /// + [Serializable] + public class XshdProperty : XshdElement + { + /// + /// Gets/sets the name. + /// + public string Name { get; set; } + + /// + /// Gets/sets the value. + /// + public string Value { get; set; } + + /// + /// Creates a new XshdColor instance. + /// + public XshdProperty() + { + } + + /// + public override object AcceptVisitor(IXshdVisitor visitor) + { + return null; +// return visitor.VisitProperty(this); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdReference.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdReference.cs new file mode 100644 index 000000000..363cd881c --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdReference.cs @@ -0,0 +1,127 @@ +// 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; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// A reference to an xshd color, or an inline xshd color. + /// + [Serializable] + public struct XshdReference : IEquatable> where T : XshdElement + { + string referencedDefinition; + string referencedElement; + T inlineElement; + + /// + /// Gets the reference. + /// + public string ReferencedDefinition { + get { return referencedDefinition; } + } + + /// + /// Gets the reference. + /// + public string ReferencedElement { + get { return referencedElement; } + } + + /// + /// Gets the inline element. + /// + public T InlineElement { + get { return inlineElement; } + } + + /// + /// Creates a new XshdReference instance. + /// + public XshdReference(string referencedDefinition, string referencedElement) + { + if (referencedElement == null) + throw new ArgumentNullException("referencedElement"); + this.referencedDefinition = referencedDefinition; + this.referencedElement = referencedElement; + this.inlineElement = null; + } + + /// + /// Creates a new XshdReference instance. + /// + public XshdReference(T inlineElement) + { + if (inlineElement == null) + throw new ArgumentNullException("inlineElement"); + this.referencedDefinition = null; + this.referencedElement = null; + this.inlineElement = inlineElement; + } + + /// + /// Applies the visitor to the inline element, if there is any. + /// + public object AcceptVisitor(IXshdVisitor visitor) + { + if (inlineElement != null) + return inlineElement.AcceptVisitor(visitor); + else + return null; + } + + #region Equals and GetHashCode implementation + // The code in this region is useful if you want to use this structure in collections. + // If you don't need it, you can just remove the region and the ": IEquatable" declaration. + + /// + public override bool Equals(object obj) + { + if (obj is XshdReference) + return Equals((XshdReference)obj); // use Equals method below + else + return false; + } + + /// + /// Equality operator. + /// + public bool Equals(XshdReference other) + { + // add comparisions for all members here + return this.referencedDefinition == other.referencedDefinition + && this.referencedElement == other.referencedElement + && this.inlineElement == other.inlineElement; + } + + /// + public override int GetHashCode() + { + // combine the hash codes of all members here (e.g. with XOR operator ^) + return GetHashCode(referencedDefinition) ^ GetHashCode(referencedElement) ^ GetHashCode(inlineElement); + } + + static int GetHashCode(object o) + { + return o != null ? o.GetHashCode() : 0; + } + + /// + /// Equality operator. + /// + public static bool operator ==(XshdReference left, XshdReference right) + { + return left.Equals(right); + } + + /// + /// Inequality operator. + /// + public static bool operator !=(XshdReference left, XshdReference right) + { + return !left.Equals(right); + } + #endregion + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdRule.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdRule.cs new file mode 100644 index 000000000..abca25f69 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdRule.cs @@ -0,0 +1,35 @@ +// 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; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// <Rule> element. + /// + [Serializable] + public class XshdRule : XshdElement + { + /// + /// Gets/sets the rule regex. + /// + public string Regex { get; set; } + + /// + /// Gets/sets the rule regex type. + /// + public XshdRegexType RegexType { get; set; } + + /// + /// Gets/sets the color reference. + /// + public XshdReference ColorReference { get; set; } + + /// + public override object AcceptVisitor(IXshdVisitor visitor) + { + return visitor.VisitRule(this); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdRuleSet.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdRuleSet.cs new file mode 100644 index 000000000..2ffa16143 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdRuleSet.cs @@ -0,0 +1,51 @@ +// 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 Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// A rule set in a XSHD file. + /// + [Serializable] + public class XshdRuleSet : XshdElement + { + /// + /// Gets/Sets the name of the rule set. + /// + public string Name { get; set; } + + /// + /// Gets/sets whether the case is ignored in expressions inside this rule set. + /// + public bool? IgnoreCase { get; set; } + + readonly NullSafeCollection elements = new NullSafeCollection(); + + /// + /// Gets the collection of elements. + /// + public IList Elements { + get { return elements; } + } + + /// + /// Applies the visitor to all elements. + /// + public void AcceptElements(IXshdVisitor visitor) + { + foreach (XshdElement element in Elements) { + element.AcceptVisitor(visitor); + } + } + + /// + public override object AcceptVisitor(IXshdVisitor visitor) + { + return visitor.VisitRuleSet(this); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdSpan.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdSpan.cs new file mode 100644 index 000000000..6d32abad4 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdSpan.cs @@ -0,0 +1,82 @@ +// 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; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// Specifies the type of the regex. + /// + public enum XshdRegexType + { + /// + /// Normal regex. Used when the regex was specified as attribute. + /// + Default, + /// + /// Ignore pattern whitespace / allow regex comments. Used when the regex was specified as text element. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", + Justification = "Using the same case as the RegexOption")] + IgnorePatternWhitespace + } + + /// + /// <Span> element. + /// + [Serializable] + public class XshdSpan : XshdElement + { + /// + /// Gets/sets the begin regex. + /// + public string BeginRegex { get; set; } + + /// + /// Gets/sets the begin regex type. + /// + public XshdRegexType BeginRegexType { get; set; } + + /// + /// Gets/sets the end regex. + /// + public string EndRegex { get; set; } + + /// + /// Gets/sets the end regex type. + /// + public XshdRegexType EndRegexType { get; set; } + + /// + /// Gets/sets whether the span is multiline. + /// + public bool Multiline { get; set; } + + /// + /// Gets/sets the rule set reference. + /// + public XshdReference RuleSetReference { get; set; } + + /// + /// Gets/sets the span color. + /// + public XshdReference SpanColorReference { get; set; } + + /// + /// Gets/sets the span begin color. + /// + public XshdReference BeginColorReference { get; set; } + + /// + /// Gets/sets the span end color. + /// + public XshdReference EndColorReference { get; set; } + + /// + public override object AcceptVisitor(IXshdVisitor visitor) + { + return visitor.VisitSpan(this); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdSyntaxDefinition.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdSyntaxDefinition.cs new file mode 100644 index 000000000..347f14d25 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Xshd/XshdSyntaxDefinition.cs @@ -0,0 +1,50 @@ +// 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 Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Highlighting.Xshd +{ + /// + /// A <SyntaxDefinition> element. + /// + [Serializable] + public class XshdSyntaxDefinition + { + /// + /// Creates a new XshdSyntaxDefinition object. + /// + public XshdSyntaxDefinition() + { + this.Elements = new NullSafeCollection(); + this.Extensions = new NullSafeCollection(); + } + + /// + /// Gets/sets the definition name + /// + public string Name { get; set; } + + /// + /// Gets the associated extensions. + /// + public IList Extensions { get; private set; } + + /// + /// Gets the collection of elements. + /// + public IList Elements { get; private set; } + + /// + /// Applies the visitor to all elements. + /// + public void AcceptElements(IXshdVisitor visitor) + { + foreach (XshdElement element in Elements) { + element.AcceptVisitor(visitor); + } + } + } +} -- cgit v1.3.1