diff options
| author | Roy Ben-Shabat <Roy@Twine-s.com> | 2020-07-27 15:39:26 +0300 |
|---|---|---|
| committer | Roy Ben-Shabat <Roy@Twine-s.com> | 2020-07-27 15:39:26 +0300 |
| commit | 5e59906df60d82248da4ae47677ed59d56fb605a (patch) | |
| tree | 8585548197bfada234b7ded17028aba9563c32de /Software/Visual_Studio/Scripting/Tango.Scripting.Editors | |
| parent | 3210901f7aa313cfe1eb2c303b539d6e7d1f2324 (diff) | |
| parent | c947fa4b4999b1368ee500c3349ef6e8fce3f0b5 (diff) | |
| download | Tango-5e59906df60d82248da4ae47677ed59d56fb605a.tar.gz Tango-5e59906df60d82248da4ae47677ed59d56fb605a.zip | |
Merge branch 'master' of https://twinetfs.visualstudio.com/_git/Tango
Diffstat (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.Editors')
10 files changed, 837 insertions, 19 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/ITextMarker.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/ITextMarker.cs new file mode 100644 index 000000000..dcbf8388a --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/ITextMarker.cs @@ -0,0 +1,169 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Media; + +namespace Tango.Scripting.Editors +{ + /// <summary> + /// Represents a text marker. + /// </summary> + public interface ITextMarker + { + /// <summary> + /// Gets the start offset of the marked text region. + /// </summary> + int StartOffset { get; } + + /// <summary> + /// Gets the end offset of the marked text region. + /// </summary> + int EndOffset { get; } + + /// <summary> + /// Gets the length of the marked region. + /// </summary> + int Length { get; } + + /// <summary> + /// Deletes the text marker. + /// </summary> + void Delete(); + + /// <summary> + /// Gets whether the text marker was deleted. + /// </summary> + bool IsDeleted { get; } + + /// <summary> + /// Event that occurs when the text marker is deleted. + /// </summary> + event EventHandler Deleted; + + /// <summary> + /// Gets/Sets the background color. + /// </summary> + Color? BackgroundColor { get; set; } + + /// <summary> + /// Gets/Sets the foreground color. + /// </summary> + Color? ForegroundColor { get; set; } + + /// <summary> + /// Gets/Sets the font weight. + /// </summary> + FontWeight? FontWeight { get; set; } + + /// <summary> + /// Gets/Sets the font style. + /// </summary> + FontStyle? FontStyle { get; set; } + + /// <summary> + /// Gets/Sets the type of the marker. Use TextMarkerType.None for normal markers. + /// </summary> + TextMarkerTypes MarkerTypes { get; set; } + + /// <summary> + /// Gets/Sets the color of the marker. + /// </summary> + Color MarkerColor { get; set; } + + /// <summary> + /// Gets/Sets an object with additional data for this text marker. + /// </summary> + object Tag { get; set; } + + /// <summary> + /// Gets/Sets an object that will be displayed as tooltip in the text editor. + /// </summary> + /// <remarks>Not supported in this sample!</remarks> + object ToolTip { get; set; } + } + + [Flags] + public enum TextMarkerTypes + { + /// <summary> + /// Use no marker + /// </summary> + None = 0x0000, + /// <summary> + /// Use squiggly underline marker + /// </summary> + SquigglyUnderline = 0x001, + /// <summary> + /// Normal underline. + /// </summary> + NormalUnderline = 0x002, + /// <summary> + /// Dotted underline. + /// </summary> + DottedUnderline = 0x004, + + /// <summary> + /// Horizontal line in the scroll bar. + /// </summary> + LineInScrollBar = 0x0100, + /// <summary> + /// Small triangle in the scroll bar, pointing to the right. + /// </summary> + ScrollBarRightTriangle = 0x0400, + /// <summary> + /// Small triangle in the scroll bar, pointing to the left. + /// </summary> + ScrollBarLeftTriangle = 0x0800, + /// <summary> + /// Small circle in the scroll bar. + /// </summary> + CircleInScrollBar = 0x1000 + } + + public interface ITextMarkerService + { + /// <summary> + /// Creates a new text marker. The text marker will be invisible at first, + /// you need to set one of the Color properties to make it visible. + /// </summary> + ITextMarker Create(int startOffset, int length); + + /// <summary> + /// Gets the list of text markers. + /// </summary> + IEnumerable<ITextMarker> TextMarkers { get; } + + /// <summary> + /// Removes the specified text marker. + /// </summary> + void Remove(ITextMarker marker); + + /// <summary> + /// Removes all text markers that match the condition. + /// </summary> + void RemoveAll(Predicate<ITextMarker> predicate); + + /// <summary> + /// Finds all text markers at the specified offset. + /// </summary> + IEnumerable<ITextMarker> GetMarkersAtOffset(int offset); + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/TextMarkerService.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/TextMarkerService.cs new file mode 100644 index 000000000..2bb3d8e03 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/TextMarkerService.cs @@ -0,0 +1,365 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Windows; +using System.Windows.Media; +using System.Windows.Threading; +using Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Rendering; + +namespace Tango.Scripting.Editors +{ + /// <summary> + /// Handles the text markers for a code editor. + /// </summary> + public sealed class TextMarkerService : DocumentColorizingTransformer, IBackgroundRenderer, ITextMarkerService, ITextViewConnect + { + TextSegmentCollection<TextMarker> markers; + TextDocument document; + + public TextMarkerService(TextDocument document) + { + if (document == null) + throw new ArgumentNullException("document"); + this.document = document; + this.markers = new TextSegmentCollection<TextMarker>(document); + } + + #region ITextMarkerService + public ITextMarker Create(int startOffset, int length) + { + if (markers == null) + throw new InvalidOperationException("Cannot create a marker when not attached to a document"); + + int textLength = document.TextLength; + if (startOffset < 0 || startOffset > textLength) + throw new ArgumentOutOfRangeException("startOffset", startOffset, "Value must be between 0 and " + textLength); + if (length < 0 || startOffset + length > textLength) + throw new ArgumentOutOfRangeException("length", length, "length must not be negative and startOffset+length must not be after the end of the document"); + + TextMarker m = new TextMarker(this, startOffset, length); + markers.Add(m); + // no need to mark segment for redraw: the text marker is invisible until a property is set + return m; + } + + public IEnumerable<ITextMarker> GetMarkersAtOffset(int offset) + { + if (markers == null) + return Enumerable.Empty<ITextMarker>(); + else + return markers.FindSegmentsContaining(offset); + } + + public IEnumerable<ITextMarker> TextMarkers { + get { return markers ?? Enumerable.Empty<ITextMarker>(); } + } + + public void RemoveAll(Predicate<ITextMarker> predicate) + { + if (predicate == null) + throw new ArgumentNullException("predicate"); + if (markers != null) { + foreach (TextMarker m in markers.ToArray()) { + if (predicate(m)) + Remove(m); + } + } + } + + public void Remove(ITextMarker marker) + { + if (marker == null) + throw new ArgumentNullException("marker"); + TextMarker m = marker as TextMarker; + if (markers != null && markers.Remove(m)) { + Redraw(m); + m.OnDeleted(); + } + } + + /// <summary> + /// Redraws the specified text segment. + /// </summary> + internal void Redraw(ISegment segment) + { + foreach (var view in textViews) { + view.Redraw(segment, DispatcherPriority.Normal); + } + if (RedrawRequested != null) + RedrawRequested(this, EventArgs.Empty); + } + + public event EventHandler RedrawRequested; + #endregion + + #region DocumentColorizingTransformer + protected override void ColorizeLine(DocumentLine line) + { + if (markers == null) + return; + int lineStart = line.Offset; + int lineEnd = lineStart + line.Length; + foreach (TextMarker marker in markers.FindOverlappingSegments(lineStart, line.Length)) { + Brush foregroundBrush = null; + if (marker.ForegroundColor != null) { + foregroundBrush = new SolidColorBrush(marker.ForegroundColor.Value); + foregroundBrush.Freeze(); + } + ChangeLinePart( + Math.Max(marker.StartOffset, lineStart), + Math.Min(marker.EndOffset, lineEnd), + element => { + if (foregroundBrush != null) { + element.TextRunProperties.SetForegroundBrush(foregroundBrush); + } + Typeface tf = element.TextRunProperties.Typeface; + element.TextRunProperties.SetTypeface(new Typeface( + tf.FontFamily, + marker.FontStyle ?? tf.Style, + marker.FontWeight ?? tf.Weight, + tf.Stretch + )); + } + ); + } + } + #endregion + + #region IBackgroundRenderer + public KnownLayer Layer { + get { + // draw behind selection + return KnownLayer.Selection; + } + } + + public void Draw(TextView textView, DrawingContext drawingContext) + { + if (textView == null) + throw new ArgumentNullException("textView"); + if (drawingContext == null) + throw new ArgumentNullException("drawingContext"); + if (markers == null || !textView.VisualLinesValid) + return; + var visualLines = textView.VisualLines; + if (visualLines.Count == 0) + return; + int viewStart = visualLines.First().FirstDocumentLine.Offset; + int viewEnd = visualLines.Last().LastDocumentLine.EndOffset; + foreach (TextMarker marker in markers.FindOverlappingSegments(viewStart, viewEnd - viewStart)) { + if (marker.BackgroundColor != null) { + BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder(); + geoBuilder.AlignToWholePixels = true; + geoBuilder.CornerRadius = 3; + geoBuilder.AddSegment(textView, marker); + Geometry geometry = geoBuilder.CreateGeometry(); + if (geometry != null) { + Color color = marker.BackgroundColor.Value; + SolidColorBrush brush = new SolidColorBrush(color); + brush.Freeze(); + drawingContext.DrawGeometry(brush, null, geometry); + } + } + var underlineMarkerTypes = TextMarkerTypes.SquigglyUnderline | TextMarkerTypes.NormalUnderline | TextMarkerTypes.DottedUnderline; + if ((marker.MarkerTypes & underlineMarkerTypes) != 0) { + foreach (Rect r in BackgroundGeometryBuilder.GetRectsForSegment(textView, marker)) { + Point startPoint = r.BottomLeft; + Point endPoint = r.BottomRight; + + Brush usedBrush = new SolidColorBrush(marker.MarkerColor); + usedBrush.Freeze(); + if ((marker.MarkerTypes & TextMarkerTypes.SquigglyUnderline) != 0) { + double offset = 2.5; + + int count = Math.Max((int)((endPoint.X - startPoint.X) / offset) + 1, 4); + + StreamGeometry geometry = new StreamGeometry(); + + using (StreamGeometryContext ctx = geometry.Open()) { + ctx.BeginFigure(startPoint, false, false); + ctx.PolyLineTo(CreatePoints(startPoint, endPoint, offset, count).ToArray(), true, false); + } + + geometry.Freeze(); + + Pen usedPen = new Pen(usedBrush, 1); + usedPen.Freeze(); + drawingContext.DrawGeometry(Brushes.Transparent, usedPen, geometry); + } + if ((marker.MarkerTypes & TextMarkerTypes.NormalUnderline) != 0) { + Pen usedPen = new Pen(usedBrush, 1); + usedPen.Freeze(); + drawingContext.DrawLine(usedPen, startPoint, endPoint); + } + if ((marker.MarkerTypes & TextMarkerTypes.DottedUnderline) != 0) { + Pen usedPen = new Pen(usedBrush, 1); + usedPen.DashStyle = DashStyles.Dot; + usedPen.Freeze(); + drawingContext.DrawLine(usedPen, startPoint, endPoint); + } + } + } + } + } + + IEnumerable<Point> CreatePoints(Point start, Point end, double offset, int count) + { + for (int i = 0; i < count; i++) + yield return new Point(start.X + i * offset, start.Y - ((i + 1) % 2 == 0 ? offset : 0)); + } + #endregion + + #region ITextViewConnect + readonly List<TextView> textViews = new List<TextView>(); + + void ITextViewConnect.AddToTextView(TextView textView) + { + if (textView != null && !textViews.Contains(textView)) { + Debug.Assert(textView.Document == document); + textViews.Add(textView); + } + } + + void ITextViewConnect.RemoveFromTextView(TextView textView) + { + if (textView != null) { + Debug.Assert(textView.Document == document); + textViews.Remove(textView); + } + } + #endregion + } + + public sealed class TextMarker : TextSegment, ITextMarker + { + readonly TextMarkerService service; + + public TextMarker(TextMarkerService service, int startOffset, int length) + { + if (service == null) + throw new ArgumentNullException("service"); + this.service = service; + this.StartOffset = startOffset; + this.Length = length; + this.markerTypes = TextMarkerTypes.None; + } + + public event EventHandler Deleted; + + public bool IsDeleted { + get { return !this.IsConnectedToCollection; } + } + + public void Delete() + { + service.Remove(this); + } + + internal void OnDeleted() + { + if (Deleted != null) + Deleted(this, EventArgs.Empty); + } + + void Redraw() + { + service.Redraw(this); + } + + Color? backgroundColor; + + public Color? BackgroundColor { + get { return backgroundColor; } + set { + if (backgroundColor != value) { + backgroundColor = value; + Redraw(); + } + } + } + + Color? foregroundColor; + + public Color? ForegroundColor { + get { return foregroundColor; } + set { + if (foregroundColor != value) { + foregroundColor = value; + Redraw(); + } + } + } + + FontWeight? fontWeight; + + public FontWeight? FontWeight { + get { return fontWeight; } + set { + if (fontWeight != value) { + fontWeight = value; + Redraw(); + } + } + } + + FontStyle? fontStyle; + + public FontStyle? FontStyle { + get { return fontStyle; } + set { + if (fontStyle != value) { + fontStyle = value; + Redraw(); + } + } + } + + public object Tag { get; set; } + + TextMarkerTypes markerTypes; + + public TextMarkerTypes MarkerTypes { + get { return markerTypes; } + set { + if (markerTypes != value) { + markerTypes = value; + Redraw(); + } + } + } + + Color markerColor; + + public Color MarkerColor { + get { return markerColor; } + set { + if (markerColor != value) { + markerColor = value; + Redraw(); + } + } + } + + public object ToolTip { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs index a05d1fc75..72c27f9a9 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs @@ -30,7 +30,7 @@ namespace Tango.Scripting.Editors.Highlighting { try { - ChangeLinePart(StartOffset, EndOffset, element => element.TextRunProperties.SetForegroundBrush(Brush)); + ChangeLinePart(StartOffset, EndOffset, element => element.TextRunProperties.SetBackgroundBrush(Brush)); } catch { } } 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 index ead5045ab..8e02db898 100644 --- 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 @@ -5,7 +5,6 @@ <Color name="StrongEmphasis" fontWeight="bold" exampleText="**this** is more important!" /> <Color name="Code" exampleText="this is `int.GetHashCode()`" /> <Color name="BlockQuote" foreground="DarkBlue" exampleText="> This is a\r\n> quote." /> - <Color name="Link" foreground="Blue" exampleText="[text](http://example.com)" /> <Color name="Image" foreground="Green" exampleText="[text][http://example.com/test.png]" /> <Color name="LineBreak" background="LightGray" exampleText="end of line \r\n2nd line " /> @@ -43,12 +42,6 @@ <Rule color="Image"> \!\[.*\]\[.*\] </Rule> - <Rule color="Link"> - \[.*\]\(.*\) - </Rule> - <Rule color="Link"> - \[.*\]\[.*\] - </Rule> <Rule color="LineBreak"> [ ]{2}$ </Rule> 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 index 8f0bdef76..50fdc0e2c 100644 --- 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 @@ -1,13 +1,13 @@ <SyntaxDefinition name="XML" extensions=".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" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008"> <Color foreground="Green" name="Comment" exampleText="<!-- comment -->" /> - <Color foreground="Blue" name="CData" exampleText="<![CDATA[data]]>" /> - <Color foreground="Blue" name="DocType" exampleText="<!DOCTYPE rootElement>" /> - <Color foreground="Blue" name="XmlDeclaration" exampleText='<?xml version="1.0"?>' /> - <Color foreground="DarkMagenta" name="XmlTag" exampleText='<tag attribute="value" />' /> - <Color foreground="Red" name="AttributeName" exampleText='<tag attribute="value" />' /> - <Color foreground="Blue" name="AttributeValue" exampleText='<tag attribute="value" />' /> + <Color foreground="#3F92D6" name="CData" exampleText="<![CDATA[data]]>" /> + <Color foreground="#C8C8C7" name="DocType" exampleText="<!DOCTYPE rootElement>" /> + <Color foreground="#3F92D6" name="XmlDeclaration" exampleText='<?xml version="1.0"?>' /> + <Color foreground="#3F92D6" name="XmlTag" exampleText='<tag attribute="value" />' /> + <Color foreground="#92CAF4" name="AttributeName" exampleText='<tag attribute="value" />' /> + <Color foreground="#C8C8C7" name="AttributeValue" exampleText='<tag attribute="value" />' /> <Color foreground="Teal" name="Entity" exampleText="index.aspx?a=1&amp;b=2" /> - <Color foreground="Olive" name="BrokenEntity" exampleText="index.aspx?a=1&b=2" /> + <Color foreground="Red" name="BrokenEntity" exampleText="index.aspx?a=1&b=2" /> <RuleSet> <Span color="Comment" multiline="true"> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs index 3dabb6b7a..1b1f12ff3 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs @@ -554,7 +554,7 @@ namespace Tango.Scripting.Editors.Rendering /// </summary> public static readonly DependencyProperty LinkTextForegroundBrushProperty = DependencyProperty.Register("LinkTextForegroundBrush", typeof(Brush), typeof(TextView), - new FrameworkPropertyMetadata(Brushes.Blue)); + new FrameworkPropertyMetadata(Brushes.Gray)); /// <summary> /// Gets/sets the Brush used for displaying link texts. diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs index 71a455f86..8cf615a7c 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel.Design; using System.Diagnostics; using System.IO; using System.Linq; @@ -56,6 +57,7 @@ namespace Tango.Scripting.Editors private List<KnownType> _knownTypes; private List<ScriptType> _declaredTypes; private bool _isLoadingTypes; + private TextMarkerService errorMarkerService; private static JsonSerializerSettings _jsonSettings; private static Dictionary<Type, KnownType> _knownTypesCache; private static String KNOWN_TYPES_CACHE_FOLDER; @@ -69,6 +71,7 @@ namespace Tango.Scripting.Editors public static event EventHandler<TangoProgressChangedEventArgs<int>> LoadingSymbolsProgress; public static event EventHandler LoadingSymbolsStarted; public static event EventHandler LoadingSymbolsCompleted; + private static event EventHandler KnownTypesAvailable; #region Mini Classes @@ -161,6 +164,14 @@ namespace Tango.Scripting.Editors public static readonly DependencyProperty AdditionalScriptsProperty = DependencyProperty.Register("AdditionalScripts", typeof(ObservableCollection<IScriptSource>), typeof(ScriptEditor), new PropertyMetadata(null)); + public Brush ColorizeBrush + { + get { return (Brush)GetValue(ColorizeBrushProperty); } + set { SetValue(ColorizeBrushProperty, value); } + } + public static readonly DependencyProperty ColorizeBrushProperty = + DependencyProperty.Register("ColorizeBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.YellowGreen) { Opacity = 0.5 })); + #endregion #region Constructors @@ -266,6 +277,8 @@ namespace Tango.Scripting.Editors _knownTypes = new List<KnownType>(); _parser = new ScriptParser(); + KnownTypesAvailable += ScriptEditor_KnownTypesAvailable; + TextArea.IndentationStrategy = new Indentation.CSharp.CSharpIndentationStrategy(Options); foldingStrategy = new BraceFoldingStrategy(); @@ -285,6 +298,18 @@ namespace Tango.Scripting.Editors completionWindow.InsertionRequest += CompletionWindow_InsertionRequest; TextChanged += ScriptEditor_TextChanged; + + errorMarkerService = new TextMarkerService(Document); + TextArea.TextView.BackgroundRenderers.Add(errorMarkerService); + TextArea.TextView.LineTransformers.Add(errorMarkerService); + } + + private void ScriptEditor_KnownTypesAvailable(object sender, EventArgs e) + { + if (sender != this) + { + InvalidateHighlightingPartial(); + } } private bool preventCodeUpdate; @@ -1357,7 +1382,7 @@ namespace Tango.Scripting.Editors return popup; } - public static void LoadUsingsSymbols(List<Assembly> assemblies, List<String> usings) + public void LoadUsingsSymbols(List<Assembly> assemblies, List<String> usings) { lock (_loadUsingsLock) { @@ -1390,6 +1415,9 @@ namespace Tango.Scripting.Editors _knownTypesCache.Add(knownType.Type, knownType); } + KnownTypesAvailable?.Invoke(this, new EventArgs()); + InvalidateHighlightingPartial(); + continue; } @@ -1575,6 +1603,100 @@ namespace Tango.Scripting.Editors // _isLoadingCachedAssemblies = false; //} + private void InvalidateHighlightingPartial() + { + List<Assembly> assemblies = new List<Assembly>(); + Dispatcher.Invoke(() => + { + assemblies = ReferenceAssemblies.ToList(); + }); + + var usings = _current_usings.ToList(); + + _knownTypes.Clear(); + + foreach (var knownType in _knownTypesCache.ToList().Select(x => x.Value).ToList()) + { + if (usings.Exists(x => knownType.Type.Namespace == x) && assemblies.Exists(x => x == knownType.Type.Assembly)) + { + lock (_knownTypes) + { + _knownTypes.Add(knownType); + } + } + } + + if (_knownTypes.Count > 0 || _declaredTypes.Count > 0) + { + String text = String.Empty; + + Stream xshd_stream = typeof(ScriptEditor).Assembly.GetManifestResourceStream("Tango.Scripting.Editors.Highlighting.Resources.CSharp-Mode.xshd"); + + using (StreamReader reader = new StreamReader(xshd_stream)) + { + text = reader.ReadToEnd(); + } + + List<String> referenceTypes = new List<string>(); + List<String> interfaceTypes = new List<string>(); + + lock (_knownTypes) + { + foreach (var type in _knownTypes.ToList().Where(x => x != null)) + { + String name = type.Name; + + if (type.Type.ContainsGenericParameters) + { + name = new String(name.TakeWhile(x => x != '`').ToArray()); + } + + if (type.Type.IsInterface || type.Type.IsEnum) + { + interfaceTypes.Add(String.Format("<Word>{0}</Word>", name)); + } + else if (type.Type.IsClass || (type.Type.IsValueType)) + { + referenceTypes.Add(String.Format("<Word>{0}</Word>", name)); + } + } + } + + foreach (var type in _declaredTypes) + { + if (type.Kind == TypeKind.Interface || type.Kind == TypeKind.Enum) + { + interfaceTypes.Add(String.Format("<Word>{0}</Word>", type.Name)); + } + else if (type.Kind == TypeKind.Class) + { + referenceTypes.Add(String.Format("<Word>{0}</Word>", type.Name)); + } + } + + if (referenceTypes.Count > 0) + { + text = text.Replace("<Word>@ReferenceTypes@</Word>", String.Join(Environment.NewLine, referenceTypes.Distinct())); + } + + if (interfaceTypes.Count > 0) + { + text = text.Replace("<Word>@InterfaceTypes@</Word>", String.Join(Environment.NewLine, interfaceTypes.Distinct())); + } + + MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text)); + + XmlTextReader xshd_reader = new XmlTextReader(ms); + + Dispatcher.Invoke(new Action(() => + { + SyntaxHighlighting = HighlightingLoader.Load(xshd_reader, HighlightingManager.Instance); + xshd_reader.Close(); + ms.Dispose(); + })); + } + } + public void InvalidateHighlighting(bool loadKnownTypes = true) { if (!_isLoadingTypes) @@ -1964,7 +2086,7 @@ namespace Tango.Scripting.Editors { int parameterIndex = expression.Count(x => x == ','); - + expression = new string(expression.TakeWhile(x => x != '(').ToArray()); var tree = expression.Split('.').Select(x => x.Remove(@"\n|\r|\s|\t|\(|\)|\[|\]|<.*>")).ToList(); @@ -2209,6 +2331,116 @@ namespace Tango.Scripting.Editors Document.Insert(TextArea.Caret.Offset, code); } + public int Find(String text) + { + if (String.IsNullOrEmpty(text)) return -1; + + string txt = Document.Text; + int index = txt.IndexOf(text, TextArea.Caret.Offset); + + if (index > -1) + { + Select(index, text.Length); + ScrollToLine(TextArea.Selection.StartPosition.Line); + } + else + { + index = txt.IndexOf(text, 0); + + if (index > -1) + { + Select(index, text.Length); + ScrollToLine(TextArea.Selection.StartPosition.Line); + } + else + { + Select(0, 0); + System.Media.SystemSounds.Beep.Play(); + } + } + + return index; + } + + public int ReplaceNext(String text, String replace) + { + if (String.IsNullOrEmpty(text)) return -1; + + String selectedText = TextArea.Selection.GetText(); + + if (selectedText == text) + { + TextArea.Selection.ReplaceSelectionWithText(replace); + } + + return Find(text); + } + + public int ReplaceAll(String text, String replace) + { + int counter = 0; + + Select(0, 0); + + while (ReplaceNext(text, replace) > -1) + { + counter++; + }; + + return counter; + } + + public void ColorizeByKeyword(String text) + { + ResetColorizationByKeyword(); + + if (String.IsNullOrEmpty(text)) return; + + var txt = Document.Text; + + var indexes = txt.AllIndexesOf(text).ToList(); + + foreach (var index in indexes) + { + Document.BeginUpdate(); + + var line = Document.GetLineByOffset(index); + + OffsetColorizer colorizer = new OffsetColorizer(line, index, index + text.Length, ColorizeBrush); + TextArea.TextView.LineTransformers.Add(colorizer); + + Document.EndUpdate(); + } + } + + public void ResetColorizationByKeyword() + { + Document.BeginUpdate(); + + for (int i = 0; i < TextArea.TextView.LineTransformers.Count; i++) + { + if (TextArea.TextView.LineTransformers[i] is OffsetColorizer) + { + TextArea.TextView.LineTransformers.RemoveAt(i); + i--; + } + } + + Document.EndUpdate(); + } + + public void HighlighError(int position, int length) + { + ITextMarker marker = errorMarkerService.Create(position, length); + marker.MarkerTypes = TextMarkerTypes.SquigglyUnderline; + marker.MarkerColor = Colors.Red; + } + + public void ClearErrors() + { + errorMarkerService.RemoveAll(m => true); + } + #endregion } } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj index 94e3c4b0b..a70bbf3de 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj @@ -196,6 +196,8 @@ <Compile Include="CodeCompletion\OverloadViewer.cs" /> <Compile Include="Converters\BooleanToVisibilityConverter.cs" /> <Compile Include="Converters\BooleanToVisibilityInversedConverter.cs" /> + <Compile Include="Errors\ITextMarker.cs" /> + <Compile Include="Errors\TextMarkerService.cs" /> <Compile Include="ExtensionMethods.cs" /> <Compile Include="Intellisense\ClassCompletionItemPopup.cs" /> <Compile Include="Intellisense\CompletionItem.cs" /> @@ -508,6 +510,7 @@ <Compile Include="Utils\ThrowUtil.cs" /> <Compile Include="Utils\Win32.cs" /> <CodeAnalysisDictionary Include="Properties\CodeAnalysisDictionary.xml" /> + <Compile Include="XamlEditor.cs" /> <Compile Include="Xml\AbstractAXmlVisitor.cs" /> <Compile Include="Xml\AXmlAttribute.cs" /> <Compile Include="Xml\AXmlAttributeCollection.cs" /> @@ -650,7 +653,7 @@ </ItemGroup> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_UseGlobalSettings="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_StartDate="2000/1/1" /> + <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UseGlobalSettings="True" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml index 414006f3a..5de763df3 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml @@ -141,6 +141,15 @@ <Setter Property="Control.Cursor" Value="/Tango.Scripting.Editors;component/themes/RightArrow.cur"/> </Style> + <Style TargetType="{x:Type local:XamlEditor}"> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"></Setter> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"></Setter> + <Setter Property="FontFamily" Value="Consolas"></Setter> + <Setter Property="FontSize" Value="13"></Setter> + <Setter Property="SyntaxHighlighting" Value="XML"></Setter> + <Setter Property="ShowLineNumbers" Value="True"></Setter> + </Style> + <Style TargetType="{x:Type local:ScriptEditor}"> <Setter Property="Background" Value="{StaticResource ScriptBackgroundBrush}"></Setter> <Setter Property="Foreground" Value="{StaticResource ScriptForegroundBrush}"></Setter> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/XamlEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/XamlEditor.cs new file mode 100644 index 000000000..22b425ba2 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/XamlEditor.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Tango.Scripting.Editors +{ + public class XamlEditor : TextEditor + { + private bool preventCodeUpdate; + + public String Xaml + { + get { return (String)GetValue(XamlProperty); } + set { SetValue(XamlProperty, value); } + } + public static readonly DependencyProperty XamlProperty = + DependencyProperty.Register("Xaml", typeof(String), typeof(XamlEditor), new PropertyMetadata(null, (d, e) => (d as XamlEditor).OnXamlChanged())); + + public XamlEditor() + { + TextChanged += XamlEditor_TextChanged; + } + + private void XamlEditor_TextChanged(object sender, EventArgs e) + { + if (!preventCodeUpdate) + { + preventCodeUpdate = true; + Xaml = Text; + preventCodeUpdate = false; + } + } + + private void OnXamlChanged() + { + if (!preventCodeUpdate) + { + preventCodeUpdate = true; + Text = Xaml; + preventCodeUpdate = false; + } + } + } +} |
