diff options
Diffstat (limited to 'Software/Visual_Studio/Scripting')
17 files changed, 2677 insertions, 1189 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs index 8ca64ca18..7500e404f 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs @@ -21,6 +21,8 @@ namespace Tango.Scripting.Basic { public class Project<T> : ExtendedObject where T : IContext { + private object _compileLock = new object(); + public String ID { get; set; } private String _name; @@ -37,6 +39,22 @@ namespace Tango.Scripting.Basic set { _description = value; RaisePropertyChangedAuto(); } } + private bool _isRunning; + [JsonIgnore] + public bool IsRunning + { + get { return _isRunning; } + set { _isRunning = value; RaisePropertyChangedAuto(); } + } + + private bool _isCompiling; + [JsonIgnore] + public bool IsCompiling + { + get { return _isCompiling; } + set { _isCompiling = value; RaisePropertyChangedAuto(); } + } + public ApartmentState ApartmentState { get; set; } public ObservableCollection<ReferenceAssembly> ReferenceAssemblies { get; set; } @@ -52,6 +70,9 @@ namespace Tango.Scripting.Basic } } + [JsonIgnore] + public List<ScriptBreakPoint> BreakPoints { get; set; } + public Project() { ID = Guid.NewGuid().ToString(); @@ -62,99 +83,121 @@ namespace Tango.Scripting.Basic Scripts = new ObservableCollection<Script>(); Scripts.CollectionChanged += (x, e) => { RaisePropertyChanged(nameof(AdditionalScripts)); }; + + BreakPoints = new List<ScriptBreakPoint>(); } public Task<CompilationResult> Compile() { return Task.Factory.StartNew<CompilationResult>(() => { - var result = new CompilationResult(); - var tempFolder = TemporaryManager.CreateFolder(Name + "_" + ID); - result.TemporaryProjectPath = tempFolder; + lock (_compileLock) + { + try + { + IsCompiling = true; + var result = new CompilationResult(); + var tempFolder = TemporaryManager.CreateFolder(Name + "_" + ID); + result.TemporaryProjectPath = tempFolder; - String mainScriptCode = String.Empty; + String mainScriptCode = String.Empty; - foreach (var script in Scripts) - { - script.LoadCount = 0; - script.LoadCharCount = 0; - String code = script.Code; - String codeFile = Path.Combine(tempFolder, script.Name); + foreach (var script in Scripts) + { + script.LoadCount = 0; + script.LoadCharCount = 0; + String code = script.Code; + String codeFile = Path.Combine(tempFolder, script.Name); - String loadingString = String.Empty; + String loadingString = String.Empty; - foreach (var file in Scripts.Where(x => !x.IsEntryPoint && script != x).Select(x => Path.Combine(tempFolder, x.Name))) - { - loadingString += $"#load \"{file}\"\n"; - script.LoadCount++; - } + foreach (var file in Scripts.Where(x => !x.IsEntryPoint && script != x).Select(x => Path.Combine(tempFolder, x.Name))) + { + loadingString += $"#load \"{file}\"\n"; + script.LoadCount++; + } - script.LoadCharCount += loadingString.Length; + script.LoadCharCount += loadingString.Length; - code = loadingString + code; + code = loadingString + code; - if (!script.IsEntryPoint) - { - //In case we use #load - //foreach (var match in Regex.Matches(code, "#load \".+\"").OfType<Match>()) - //{ - // String line = match.ToString(); - // var pathMatch = Regex.Match(line, "(?<=\")(.*?)(?=\")"); - // if (pathMatch.Success) - // { - // String path = pathMatch.ToString(); + int debugLinesLength = 0; - // if (!System.IO.Path.IsPathRooted(path)) - // { - // StringBuilder builder = new StringBuilder(code); - // builder.Insert(match.Index + pathMatch.Index, System.IO.Path.GetFullPath(tempFolder + "\\")); - // code = builder.ToString(); - // } - // } - //} - File.WriteAllText(codeFile, code); - } - else - { - code += Environment.NewLine + Environment.NewLine + "new Program().OnExecute(GlobalContext);"; - mainScriptCode = code; - } - } + foreach (var breakPoint in BreakPoints.Where(x => x.Script == script).OrderBy(x => x.LineNumber)) + { + var debugLine = $"context.BreakPoint(\"{script.Name}\",{breakPoint.LineNumber}"; - var scriptOptions = ScriptOptions.Default.WithReferences(LoadReferenceAssemblies()); + foreach (var symbol in breakPoint.ContextSymbols) + { + debugLine += $",\"{symbol.Name}\",{symbol.Offset},{symbol.Length},{symbol.Name}"; + } - var s = CSharpScript.Create<object>(mainScriptCode, scriptOptions, typeof(GlobalObject<T>)); - result.Script = s; + debugLine += ");"; - var compileResults = s.Compile(); + StringBuilder builder = new StringBuilder(code); + builder.Insert(breakPoint.LineStartOffset + loadingString.Length + debugLinesLength, debugLine); + code = builder.ToString(); - GC.Collect(); + debugLinesLength += debugLine.Length; + } - foreach (var error in compileResults.Where(x => x.Severity == Microsoft.CodeAnalysis.DiagnosticSeverity.Error)) - { - CompilationError cError = new CompilationError(); - cError.File = System.IO.Path.GetFileName(error.Location.SourceTree.FilePath); - if (cError.File == String.Empty) + if (!script.IsEntryPoint) + { + File.WriteAllText(codeFile, code); + } + else + { + code += Environment.NewLine + Environment.NewLine + "new Program().OnExecute(GlobalContext);"; + mainScriptCode = code; + } + } + + var scriptOptions = ScriptOptions.Default.WithReferences(LoadReferenceAssemblies()).WithEmitDebugInformation(true); + + var s = CSharpScript.Create<object>(mainScriptCode, scriptOptions, typeof(GlobalObject<T>)); + + result.Script = s; + + var compileResults = s.Compile(); + + GC.Collect(); + + foreach (var error in compileResults.Where(x => x.Severity == Microsoft.CodeAnalysis.DiagnosticSeverity.Error)) + { + CompilationError cError = new CompilationError(); + cError.File = System.IO.Path.GetFileName(error.Location.SourceTree.FilePath); + if (cError.File == String.Empty) + { + cError.File = Scripts.Single(x => x.IsEntryPoint).Name; + } + Script errorScript = Scripts.Single(x => x.Name == cError.File); + cError.Message = error.GetMessage(); + cError.Severity = error.Severity; + cError.Position = error.Location.SourceSpan.Start - (errorScript != null ? errorScript.LoadCharCount : 0); + var line = error.Location.GetMappedLineSpan(); + cError.Line = line.StartLinePosition.Line + 1 - (errorScript != null ? errorScript.LoadCount : 0); + cError.Column = line.StartLinePosition.Character + 1; + cError.Length = line.EndLinePosition.Character - line.StartLinePosition.Character; + result.Errors.Add(cError); + } + + return result; + } + catch (Exception) + { + throw; + } + finally { - cError.File = Scripts.Single(x => x.IsEntryPoint).Name; + IsCompiling = false; } - Script errorScript = Scripts.Single(x => x.Name == cError.File); - cError.Message = error.GetMessage(); - cError.Severity = error.Severity; - cError.Position = error.Location.SourceSpan.Start - (errorScript != null ? errorScript.LoadCharCount : 0); - var line = error.Location.GetMappedLineSpan(); - cError.Line = line.StartLinePosition.Line + 1 - (errorScript != null ? errorScript.LoadCount : 0); - cError.Column = line.StartLinePosition.Character + 1; - cError.Length = line.EndLinePosition.Character - line.StartLinePosition.Character; - result.Errors.Add(cError); } - - return result; }); } public async Task<ProjectSession<T>> Run(T context) { + IsRunning = true; var result = await Compile(); if (result.Errors.Count > 0) @@ -175,6 +218,7 @@ namespace Tango.Scripting.Basic try { var runResult = result.Script.RunAsync(globals: new GlobalObject<T>() { GlobalContext = context }).Result; + IsRunning = false; session.Completed(runResult.ReturnValue); } catch (ThreadAbortException) @@ -187,7 +231,9 @@ namespace Tango.Scripting.Basic } finally { + BreakPoints.Clear(); GC.Collect(); + IsRunning = false; } }); diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/BreakPoint.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/BreakPoint.cs new file mode 100644 index 000000000..e847ea03e --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/BreakPoint.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Core +{ + public class BreakPoint + { + public int LineNumber { get; set; } + public bool IsActive { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPoint.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPoint.cs new file mode 100644 index 000000000..626c1abc6 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPoint.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Scripting.Core; + +namespace Tango.Scripting.Core +{ + public class ScriptBreakPoint + { + public IScriptSource Script { get; set; } + public int LineNumber { get; set; } + public int LineStartOffset { get; set; } + public int LineEndOffset { get; set; } + public List<ScriptBreakPointSymbol> ContextSymbols { get; set; } + + public ScriptBreakPoint() + { + ContextSymbols = new List<ScriptBreakPointSymbol>(); + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPointSymbol.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPointSymbol.cs new file mode 100644 index 000000000..8da35fe55 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/ScriptBreakPointSymbol.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Core +{ + public class ScriptBreakPointSymbol + { + public String Name { get; set; } + public int Offset { get; set; } + public int Length { get; set; } + public Object SymbolObject { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Tango.Scripting.Core.csproj b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Tango.Scripting.Core.csproj index aa4bbb240..bb623a4fe 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Tango.Scripting.Core.csproj +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Core/Tango.Scripting.Core.csproj @@ -41,8 +41,11 @@ <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> + <Compile Include="BreakPoint.cs" /> <Compile Include="IScriptSource.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="ScriptBreakPoint.cs" /> + <Compile Include="ScriptBreakPointSymbol.cs" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs new file mode 100644 index 000000000..1728bb565 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.Scripting.Core; + +namespace Tango.Scripting.Editors +{ + public class BreakPointSymbolPressedEventArgs : EventArgs + { + public ScriptBreakPointSymbol BreakPointSymbol { get; set; } + public Point Position { get; set; } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs new file mode 100644 index 000000000..e566e6aa9 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Media.TextFormatting; +using Tango.Scripting.Core; +using Tango.Scripting.Editors.Document; +using Tango.Scripting.Editors.Rendering; +using Tango.Scripting.Editors.Utils; + +namespace Tango.Scripting.Editors.Editing +{ + public class BreakPointMargin : AbstractMargin, IWeakEventListener + { + private TextArea textArea; + private int maxLineNumberLength = 1; + private BitmapSource _arrowBitmap; + private ScriptEditor _editor; + + public ObservableCollection<BreakPoint> BreakPoints { get; set; } + + public Brush Background + { + get { return (Brush)GetValue(BackgroundProperty); } + set { SetValue(BackgroundProperty, value); } + } + public static readonly DependencyProperty BackgroundProperty = + DependencyProperty.Register("Background", typeof(Brush), typeof(BreakPointMargin), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(50, 50, 50)))); + + public Brush Foreground + { + get { return (Brush)GetValue(ForegroundProperty); } + set { SetValue(ForegroundProperty, value); } + } + public static readonly DependencyProperty ForegroundProperty = + DependencyProperty.Register("Foreground", typeof(Brush), typeof(BreakPointMargin), new PropertyMetadata(Brushes.Red)); + + static BreakPointMargin() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(BreakPointMargin), + new FrameworkPropertyMetadata(typeof(BreakPointMargin))); + } + + public BreakPointMargin(ScriptEditor editor) + { + _editor = editor; + BreakPoints = new ObservableCollection<BreakPoint>(); + BreakPoints.CollectionChanged += BreakPoints_CollectionChanged; + RenderOptions.SetEdgeMode(this, EdgeMode.Unspecified); + + _arrowBitmap = new BitmapImage(new Uri($"pack://application:,,,/Tango.Scripting.Editors;component/Images/break_point_arrow.png", UriKind.Absolute)); + } + + private void BreakPoints_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + InvalidateVisual(); + } + + protected override Size MeasureOverride(Size availableSize) + { + return new Size(20, 0); + } + + protected override void OnRender(DrawingContext drawingContext) + { + TextView textView = this.TextView; + Size renderSize = this.RenderSize; + if (textView != null && textView.VisualLinesValid) + { + drawingContext.DrawRectangle(Background, new Pen(Background, 1), new Rect(0, 0, ActualWidth, ActualHeight)); + + var foreground = Foreground; + foreach (VisualLine line in textView.VisualLines) + { + int lineNumber = line.FirstDocumentLine.LineNumber; + + BreakPoint b = BreakPoints.FirstOrDefault(x => x.LineNumber == lineNumber); + + if (b != null) + { + double y = line.GetTextLineVisualYPosition(line.TextLines[0], VisualYPosition.TextTop); + drawingContext.DrawEllipse(Foreground, new Pen(Brushes.Gainsboro, 1), new Point(10, y - textView.VerticalOffset + 8), 6, 6); + + if (b.IsActive) + { + drawingContext.DrawImage(_arrowBitmap, new Rect(6, y - textView.VerticalOffset + 2.5, 8.5, 10)); + } + } + } + } + } + + protected override void OnTextViewChanged(TextView oldTextView, TextView newTextView) + { + if (oldTextView != null) + { + oldTextView.VisualLinesChanged -= TextViewVisualLinesChanged; + } + base.OnTextViewChanged(oldTextView, newTextView); + if (newTextView != null) + { + newTextView.VisualLinesChanged += TextViewVisualLinesChanged; + + // find the text area belonging to the new text view + textArea = newTextView.Services.GetService(typeof(TextArea)) as TextArea; + } + else + { + textArea = null; + } + InvalidateVisual(); + } + + protected override void OnDocumentChanged(TextDocument oldDocument, TextDocument newDocument) + { + if (oldDocument != null) + { + PropertyChangedEventManager.RemoveListener(oldDocument, this, "LineCount"); + } + base.OnDocumentChanged(oldDocument, newDocument); + if (newDocument != null) + { + PropertyChangedEventManager.AddListener(newDocument, this, "LineCount"); + } + OnDocumentLineCountChanged(); + } + + protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + if (managerType == typeof(PropertyChangedEventManager)) + { + OnDocumentLineCountChanged(); + return true; + } + return false; + } + + bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + return ReceiveWeakEvent(managerType, sender, e); + } + + private void OnDocumentLineCountChanged() + { + int documentLineCount = Document != null ? Document.LineCount : 1; + int newLength = documentLineCount.ToString(CultureInfo.CurrentCulture).Length; + + foreach (var breakPoint in BreakPoints.ToList()) + { + if (breakPoint.LineNumber > documentLineCount) + { + BreakPoints.Remove(breakPoint); + } + else + { + try + { + var line = Document.GetLineByNumber(breakPoint.LineNumber); + if (line != null) + { + String lineText = Document.GetText(line.Offset, line.Length); + if (!IsBreakPointValid(lineText)) + { + BreakPoints.Remove(breakPoint); + } + } + } + catch { } + } + } + + // The margin looks too small when there is only one digit, so always reserve space for + // at least two digits + if (newLength < 2) + newLength = 2; + + if (newLength != maxLineNumberLength) + { + maxLineNumberLength = newLength; + InvalidateMeasure(); + } + } + + private void TextViewVisualLinesChanged(object sender, EventArgs e) + { + InvalidateVisual(); + } + + protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) + { + // accept clicks even when clicking on the background + return new PointHitTestResult(this, hitTestParameters.HitPoint); + } + + private VisualLine GetLineNumberByMousePosition(MouseEventArgs e) + { + Point pos = e.GetPosition(TextView); + pos.X = 0; + pos.Y += TextView.VerticalOffset; + VisualLine vl = TextView.GetVisualLineFromVisualTop(pos.Y); + return vl; + } + + private bool IsBreakPointValid(String lineText) + { + if (lineText.EndsWith(";") && !lineText.StartsWith("using")) + { + return true; + } + + return false; + } + + protected override void OnPreviewMouseMove(MouseEventArgs e) + { + base.OnPreviewMouseMove(e); + + if (_editor.DisableBreakPoints) + { + Cursor = Cursors.No; + } + else + { + Cursor = Cursors.Arrow; + } + } + + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + if (_editor.DisableBreakPoints) + { + return; + } + + try + { + if (!e.Handled && TextView != null && textArea != null) + { + e.Handled = true; + textArea.Focus(); + + var visualLine = GetLineNumberByMousePosition(e); + + int? lineNumber = visualLine != null ? (int?)visualLine.FirstDocumentLine.LineNumber : null; + + if (lineNumber != null) + { + var breakPoint = BreakPoints.FirstOrDefault(x => x.LineNumber == lineNumber.Value); + if (breakPoint != null) + { + BreakPoints.Remove(breakPoint); + } + else + { + var lineText = Document.GetText(visualLine.FirstDocumentLine.Offset, visualLine.FirstDocumentLine.Length).Trim(); + + if (IsBreakPointValid(lineText)) + { + BreakPoint newBreakPoint = new BreakPoint(); + newBreakPoint.LineNumber = lineNumber.Value; + BreakPoints.Add(newBreakPoint); + } + } + } + } + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + } +} 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 index 6f400c4f5..1f6139ff6 100644 --- 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 @@ -11,7 +11,7 @@ <Color name="InterfaceTypes" foreground="#B5CE8A" exampleText="object o;" /> <Color name="MethodCall" foreground="Gainsboro" exampleText="o.ToString();"/> <Color name="NumberLiteral" foreground="#B5CE8A" exampleText="3.1415f"/> - <Color name="ThisOrBaseReference" exampleText="this.Do(); base.Do();"/> + <Color name="ThisOrBaseReference" foreground="#3F8FD6" exampleText="this.Do(); base.Do();"/> <Color name="NullOrValueKeywords" exampleText="if (value == null)"/> <Color name="Keywords" foreground="#3F8FD6" exampleText="if (a) {} else {}"/> <Color name="GotoKeywords" foreground="#3F8FD6" exampleText="continue; return null;"/> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png Binary files differnew file mode 100644 index 000000000..e8d367028 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/HideIntellisenseAttribute.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/HideIntellisenseAttribute.cs new file mode 100644 index 000000000..548bd909e --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/HideIntellisenseAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Editors.Intellisense +{ + public class HideIntellisenseAttribute : Attribute + { + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs index 3dc796152..c2e7ac422 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs @@ -137,6 +137,8 @@ namespace Tango.Scripting.Editors.Intellisense { var method = methods[i]; + if (method.GetCustomAttribute<HideIntellisenseAttribute>() != null) continue; + KnownTypeMethod m = new KnownTypeMethod(this); m.Name = method.Name; m.ReturnType = method.ReturnType; @@ -183,17 +185,14 @@ namespace Tango.Scripting.Editors.Intellisense //Load Properties { - if (Type == typeof(Color)) - { - - } - var properties = Type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static).ToList(); for (int i = 0; i < properties.Count; i++) { var property = properties[i]; + if (property.GetCustomAttribute<HideIntellisenseAttribute>() != null) continue; + KnownTypeProperty p = new KnownTypeProperty(this); p.Name = property.Name; p.ReturnType = property.PropertyType; @@ -211,6 +210,8 @@ namespace Tango.Scripting.Editors.Intellisense { var ev = events[i]; + if (ev.GetCustomAttribute<HideIntellisenseAttribute>() != null) continue; + KnownTypeEvent p = new KnownTypeEvent(this); p.Name = ev.Name; diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs index 0802cf456..6c248b63d 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -47,7 +47,10 @@ namespace Tango.Scripting.Editors private char[] word_separators = { ' ', '\t', '\n', '.', '(', ',', '-', '*', '/', '+', '$', '=', '<', '>' }; private string[] _blocking_type_words = { "class", "void" }; + public event EventHandler<BreakPointSymbolPressedEventArgs> BreakPointSymbolPressed; + private DispatcherTimer _update_timer; + private BreakPointMargin breakPointMargin; private Popup _popup; private FoldingManager foldingManager; private BraceFoldingStrategy foldingStrategy; @@ -58,6 +61,11 @@ namespace Tango.Scripting.Editors private List<ScriptType> _declaredTypes; private bool _isLoadingTypes; private TextMarkerService errorMarkerService; + private List<ScriptBreakPointSymbol> _breakPointSymbols; + private int _breakPointLineNumber; + private ScriptBreakPointSymbol _currentBreakPointSymbol; + private Point _currentBreakPointSymbolPosition; + private static JsonSerializerSettings _jsonSettings; private static Dictionary<Type, KnownType> _knownTypesCache; private static String KNOWN_TYPES_CACHE_FOLDER; @@ -191,6 +199,47 @@ namespace Tango.Scripting.Editors public static readonly DependencyProperty ColorizeBrushProperty = DependencyProperty.Register("ColorizeBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.YellowGreen) { Opacity = 0.5 })); + public Brush ErrorLineBrush + { + get { return (Brush)GetValue(ErrorLineBrushProperty); } + set { SetValue(ErrorLineBrushProperty, value); } + } + public static readonly DependencyProperty ErrorLineBrushProperty = + DependencyProperty.Register("ErrorLineBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.Red) { Opacity = 0.5 })); + + public Brush DebugLineBrush + { + get { return (Brush)GetValue(DebugLineBrushProperty); } + set { SetValue(DebugLineBrushProperty, value); } + } + public static readonly DependencyProperty DebugLineBrushProperty = + DependencyProperty.Register("DebugLineBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.Gray) { Opacity = 0.5 })); + + public Brush BreakPointLineBrush + { + get { return (Brush)GetValue(BreakPointLineBrushProperty); } + set { SetValue(BreakPointLineBrushProperty, value); } + } + public static readonly DependencyProperty BreakPointLineBrushProperty = + DependencyProperty.Register("BreakPointLineBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.Yellow) { Opacity = 0.5 })); + + public IScriptSource ScriptSource + { + get { return (IScriptSource)GetValue(ScriptSourceProperty); } + set { SetValue(ScriptSourceProperty, value); } + } + public static readonly DependencyProperty ScriptSourceProperty = + DependencyProperty.Register("ScriptSource", typeof(IScriptSource), typeof(ScriptEditor), new PropertyMetadata(null)); + + public bool DisableBreakPoints + { + get { return (bool)GetValue(DisableBreakPointsProperty); } + set { SetValue(DisableBreakPointsProperty, value); } + } + public static readonly DependencyProperty DisableBreakPointsProperty = + DependencyProperty.Register("DisableBreakPoints", typeof(bool), typeof(ScriptEditor), new PropertyMetadata(false)); + + #endregion #region Constructors @@ -329,6 +378,17 @@ namespace Tango.Scripting.Editors TextArea.TextView.LineTransformers.Add(errorMarkerService); Unloaded += ScriptEditor_Unloaded; + + breakPointMargin = new BreakPointMargin(this); + _breakPointSymbols = new List<ScriptBreakPointSymbol>(); + Loaded += ScriptEditor_Loaded; + + MouseMove += ScriptEditor_MouseMove; + } + + private void ScriptEditor_Loaded(object sender, RoutedEventArgs e) + { + TextArea.LeftMargins.Insert(0, breakPointMargin); } private void ScriptEditor_Unloaded(object sender, RoutedEventArgs e) @@ -492,6 +552,8 @@ namespace Tango.Scripting.Editors private void TextArea_TextEntered(object sender, TextCompositionEventArgs e) { + if (IsReadOnly) return; + try { List<Object> items = new List<object>(); @@ -2486,6 +2548,246 @@ namespace Tango.Scripting.Editors errorMarkerService.RemoveAll(m => true); } + public void HighlightErrorLine(int lineNumber) + { + Document.BeginUpdate(); + + var line = Document.GetLineByNumber(lineNumber); + OffsetColorizer errorLineColrizer = new OffsetColorizer(line, line.Offset, line.EndOffset, ErrorLineBrush); + TextArea.TextView.LineTransformers.Add(errorLineColrizer); + + Document.EndUpdate(); + } + + public void HighlightDebugLine(int lineNumber) + { + Document.BeginUpdate(); + + var line = Document.GetLineByNumber(lineNumber); + OffsetColorizer errorLineColrizer = new OffsetColorizer(line, line.Offset, line.EndOffset, DebugLineBrush); + TextArea.TextView.LineTransformers.Add(errorLineColrizer); + + Document.EndUpdate(); + } + + public void HighlightBreakPoint(int lineNumber, List<ScriptBreakPointSymbol> symbols) + { + _breakPointLineNumber = lineNumber; + _breakPointSymbols = symbols.ToList(); + _currentBreakPointSymbol = null; + + Document.BeginUpdate(); + + var line = Document.GetLineByNumber(lineNumber); + OffsetColorizer errorLineColrizer = new OffsetColorizer(line, line.Offset, line.EndOffset, BreakPointLineBrush); + TextArea.TextView.LineTransformers.Add(errorLineColrizer); + + var breakPoint = breakPointMargin.BreakPoints.FirstOrDefault(x => x.LineNumber == lineNumber); + breakPoint.IsActive = true; + breakPointMargin.InvalidateVisual(); + + Document.EndUpdate(); + } + + public void ResetBreakPointLine() + { + _breakPointSymbols = new List<ScriptBreakPointSymbol>(); + _currentBreakPointSymbol = null; + ResetColorizationByKeyword(); + breakPointMargin.BreakPoints.ToList().ForEach(x => x.IsActive = false); + Mouse.OverrideCursor = null; + ClearErrors(); + breakPointMargin.InvalidateVisual(); + } + + public Point? GetLineVisualPosition(int lineNumber) + { + double top = TextArea.TextView.GetVisualTopByDocumentLine(lineNumber); + var visualLine = TextArea.TextView.GetVisualLine(lineNumber); + + if (visualLine != null) + { + var textLine = visualLine.GetTextLine(0); + var x = visualLine.GetTextLineVisualXPosition(textLine, visualLine.VisualLengthWithEndOfLineMarker); + var left = visualLine.VisualLengthWithEndOfLineMarker; + return new Point(x, top); + } + + return null; + } + + public List<ScriptBreakPoint> GetBreakPoints() + { + List<ScriptBreakPoint> breakPoints = new List<ScriptBreakPoint>(); + + foreach (var b in breakPointMargin.BreakPoints) + { + ScriptBreakPoint breakPoint = new ScriptBreakPoint(); + breakPoint.Script = ScriptSource; + breakPoint.LineNumber = b.LineNumber; + + var line = Document.GetLineByNumber(b.LineNumber); + breakPoint.LineStartOffset = line.Offset; + breakPoint.LineEndOffset = line.EndOffset; + + var symbols = _parser.GetContextSymbols(Document.Text, line.Offset); + + foreach (var symbol in symbols.Where(x => (x.Kind == SymbolKind.Property || x.Kind == SymbolKind.Field || x.Kind == SymbolKind.Local || x.Kind == SymbolKind.Parameter) && !x.IsUnassigned)) + { + if (symbol.Offset < line.Offset) + { + breakPoint.ContextSymbols.Add(new ScriptBreakPointSymbol() + { + Name = symbol.Name, + Offset = symbol.Offset, + Length = symbol.Length, + }); + } + } + + breakPoints.Add(breakPoint); + } + + return breakPoints; + } + + #endregion + + #region BreakPoint Symbols Search + + private void ScriptEditor_MouseMove(object sender, MouseEventArgs e) + { + if (IsReadOnly && _breakPointSymbols.Count > 0) + { + try + { + var word_separators_plus = word_separators.ToList(); + word_separators_plus.Add(')'); + word_separators_plus.Add(';'); + + var textView = TextArea.TextView; + Point position = e.GetPosition(textView); + position.Y += textView.VerticalOffset; + VisualLine visualLine = textView.GetVisualLineFromVisualTop(position.Y); + int columnIndex = visualLine.GetVisualColumnFloor(position, false); + String line = Document.GetText(visualLine.FirstDocumentLine.Offset, visualLine.FirstDocumentLine.Length); + if (columnIndex < line.Length) + { + int wordStartIndex = columnIndex; + int wordEndIndex = columnIndex; + + while (wordStartIndex > 0) + { + if (word_separators_plus.Contains(line[wordStartIndex])) break; + wordStartIndex--; + } + + while (wordEndIndex < line.Length) + { + if (word_separators_plus.Contains(line[wordEndIndex])) break; + wordEndIndex++; + } + + if (wordStartIndex > 0) + { + wordStartIndex++; + } + + String word = line.Substring(wordStartIndex, wordEndIndex - wordStartIndex); + + var breakPointSymbol = _breakPointSymbols.FirstOrDefault(x => x.Name == word); + + if (breakPointSymbol != null) + { + int wordStartOffset = visualLine.FirstDocumentLine.Offset + wordStartIndex; + + ClearErrors(); + ITextMarker marker = errorMarkerService.Create(wordStartOffset, word.Length); + marker.MarkerTypes = TextMarkerTypes.NormalUnderline; + marker.MarkerColor = Colors.Yellow; + Mouse.OverrideCursor = Cursors.Hand; + + _currentBreakPointSymbol = breakPointSymbol; + _currentBreakPointSymbolPosition = visualLine.GetVisualPosition(wordEndIndex, VisualYPosition.LineTop); + } + else + { + _currentBreakPointSymbol = null; + Mouse.OverrideCursor = null; + ClearErrors(); + } + } + else + { + _currentBreakPointSymbol = null; + Mouse.OverrideCursor = null; + ClearErrors(); + } + } + catch (Exception ex) + { + _currentBreakPointSymbol = null; + Mouse.OverrideCursor = null; + ClearErrors(); + Debug.WriteLine(ex.Message); + } + } + } + + protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e) + { + base.OnPreviewMouseLeftButtonUp(e); + + if (_currentBreakPointSymbol != null) + { + Mouse.OverrideCursor = null; + Debug.WriteLine($"Pressed on break point symbol: {_currentBreakPointSymbol.Name}"); + BreakPointSymbolPressed?.Invoke(this, new BreakPointSymbolPressedEventArgs() + { + BreakPointSymbol = _currentBreakPointSymbol, + Position = _currentBreakPointSymbolPosition + }); + } + } + + public String GetCaretWord() + { + try + { + var word_separators_plus = word_separators.ToList(); + word_separators_plus.Add(')'); + word_separators_plus.Add(';'); + + int wordStartOffset = CaretOffset; + int wordEndOffset = CaretOffset; + + while (wordStartOffset > 0) + { + if (word_separators_plus.Contains(Document.Text[wordStartOffset])) break; + wordStartOffset--; + } + + while (wordEndOffset < Document.Text.Length) + { + if (word_separators_plus.Contains(Document.Text[wordEndOffset])) break; + wordEndOffset++; + } + + if (wordStartOffset > 0) + { + wordStartOffset++; + } + + String word = Document.Text.Substring(wordStartOffset, wordEndOffset - wordStartOffset); + + return word; + } + catch + { + return null; + } + } + #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 a70bbf3de..11e023f86 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 @@ -180,6 +180,7 @@ <Link>GlobalVersionInfo.cs</Link> </Compile> <Compile Include="AvalonEditCommands.cs" /> + <Compile Include="BreakPointSymbolPressedEventArgs.cs" /> <Compile Include="CachedAssembly.cs" /> <Compile Include="CachedUsing.cs" /> <Compile Include="CodeCompletion\CompletionListBox.cs" /> @@ -196,6 +197,7 @@ <Compile Include="CodeCompletion\OverloadViewer.cs" /> <Compile Include="Converters\BooleanToVisibilityConverter.cs" /> <Compile Include="Converters\BooleanToVisibilityInversedConverter.cs" /> + <Compile Include="Editing\BreakPointMargin.cs" /> <Compile Include="Errors\ITextMarker.cs" /> <Compile Include="Errors\TextMarkerService.cs" /> <Compile Include="ExtensionMethods.cs" /> @@ -207,6 +209,7 @@ <Compile Include="Intellisense\EventCompletionItem.cs" /> <Compile Include="Intellisense\FieldCompletionItem.cs" /> <Compile Include="Intellisense\FieldCompletionItemPopup.cs" /> + <Compile Include="Intellisense\HideIntellisenseAttribute.cs" /> <Compile Include="Intellisense\ICompletionItem.cs" /> <Compile Include="Intellisense\ICompletionProvider.cs" /> <Compile Include="Intellisense\InterfaceCompletionItem.cs" /> @@ -651,6 +654,9 @@ <ItemGroup> <Resource Include="Images\snippet.png" /> </ItemGroup> + <ItemGroup> + <Resource Include="Images\break_point_arrow.png" /> + </ItemGroup> <ProjectExtensions> <VisualStudio> <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UseGlobalSettings="True" /> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors_di35u2uj_wpftmp.csproj b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors_di35u2uj_wpftmp.csproj new file mode 100644 index 000000000..70a4840c4 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors_di35u2uj_wpftmp.csproj @@ -0,0 +1,628 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <ProjectGuid>{DA62FA39-668B-47A6-B0F2-D2C1DAF777B0}</ProjectGuid> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <OutputType>Library</OutputType> + <RootNamespace>Tango.Scripting.Editors</RootNamespace> + <AssemblyName>Tango.Scripting.Editors</AssemblyName> + <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> + <AppDesignerFolder>Properties</AppDesignerFolder> + <SourceAnalysisOverrideSettingsFile>"C:\Program Files\SharpDevelop\3.0\bin\..\AddIns\AddIns\Misc\SourceAnalysis\Settings.SourceAnalysis"</SourceAnalysisOverrideSettingsFile> + <AllowUnsafeBlocks>False</AllowUnsafeBlocks> + <NoStdLib>False</NoStdLib> + <WarningLevel>4</WarningLevel> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + <SignAssembly>false</SignAssembly> + <AssemblyOriginatorKeyFile>ICSharpCode.AvalonEdit.snk</AssemblyOriginatorKeyFile> + <DelaySign>False</DelaySign> + <AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode> + <RunCodeAnalysis>False</RunCodeAnalysis> + <CodeAnalysisRules>-Microsoft.Design#CA1020;-Microsoft.Design#CA1033;-Microsoft.Performance#CA1805;-Microsoft.Performance#CA1810</CodeAnalysisRules> + <OutputPath>..\bin\$(Configuration)</OutputPath> + <DocumentationFile>..\bin\$(Configuration)\ICSharpCode.AvalonEdit.xml</DocumentationFile> + <NoWarn>1607</NoWarn> + <TargetFrameworkProfile> + </TargetFrameworkProfile> + <SccProjectName>SAK</SccProjectName> + <SccLocalPath>SAK</SccLocalPath> + <SccAuxPath>SAK</SccAuxPath> + <SccProvider>SAK</SccProvider> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>Full</DebugType> + <Optimize>False</Optimize> + <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> + <DefineConstants>DEBUG;TRACE;DOTNET4</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> + <DebugSymbols>false</DebugSymbols> + <DebugType>PdbOnly</DebugType> + <Optimize>True</Optimize> + <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> + <DefineConstants>TRACE;DOTNET4</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' "> + <RegisterForComInterop>False</RegisterForComInterop> + <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> + <BaseAddress>4194304</BaseAddress> + <PlatformTarget>AnyCPU</PlatformTarget> + <FileAlignment>4096</FileAlignment> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'"> + <OutputPath>..\..\Build\Scripting\Debug\</OutputPath> + <DocumentationFile> + </DocumentationFile> + <Prefer32Bit>false</Prefer32Bit> + <DefineConstants>TRACE;DEBUG</DefineConstants> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'"> + <Prefer32Bit>false</Prefer32Bit> + <OutputPath>..\..\Build\Scripting\Release\</OutputPath> + <DocumentationFile /> + </PropertyGroup> + <PropertyGroup> + <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + </PropertyGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <Compile Include="..\..\Versioning\GlobalVersionInfo.cs"> + <Link>GlobalVersionInfo.cs</Link> + </Compile> + <Compile Include="AvalonEditCommands.cs" /> + <Compile Include="CachedAssembly.cs" /> + <Compile Include="CachedUsing.cs" /> + <Compile Include="CodeCompletion\CompletionListBox.cs" /> + <Compile Include="CodeCompletion\CompletionListBoxItem.cs" /> + <Compile Include="CodeCompletion\CompletionWindowBase.cs" /> + <Compile Include="CodeCompletion\CompletionList.cs" /> + <Compile Include="CodeCompletion\CompletionWindow.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="CodeCompletion\ICompletionData.cs" /> + <Compile Include="CodeCompletion\InsightWindow.cs" /> + <Compile Include="CodeCompletion\IOverloadProvider.cs" /> + <Compile Include="CodeCompletion\OverloadInsightWindow.cs" /> + <Compile Include="CodeCompletion\OverloadViewer.cs" /> + <Compile Include="Converters\BooleanToVisibilityConverter.cs" /> + <Compile Include="Converters\BooleanToVisibilityInversedConverter.cs" /> + <Compile Include="Editing\BreakPoint.cs" /> + <Compile Include="Editing\BreakPointMargin.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" /> + <Compile Include="Intellisense\CompletionItemPopupControl.cs" /> + <Compile Include="Intellisense\EnumCompletionItem.cs" /> + <Compile Include="Intellisense\EnumCompletionItemPopup.cs" /> + <Compile Include="Intellisense\EventCompletionItem.cs" /> + <Compile Include="Intellisense\FieldCompletionItem.cs" /> + <Compile Include="Intellisense\FieldCompletionItemPopup.cs" /> + <Compile Include="Intellisense\ICompletionItem.cs" /> + <Compile Include="Intellisense\ICompletionProvider.cs" /> + <Compile Include="Intellisense\InterfaceCompletionItem.cs" /> + <Compile Include="Intellisense\InterfaceCompletionItemPopup.cs" /> + <Compile Include="Intellisense\KnownType.cs" /> + <Compile Include="Document\ChangeTrackingCheckpoint.cs" /> + <Compile Include="Document\DocumentChangeOperation.cs"> + <DependentUpon>UndoStack.cs</DependentUpon> + </Compile> + <Compile Include="Document\ILineTracker.cs" /> + <Compile Include="Document\ISegment.cs" /> + <Compile Include="Document\ITextSource.cs" /> + <Compile Include="Document\IUndoableOperation.cs"> + <DependentUpon>UndoStack.cs</DependentUpon> + </Compile> + <Compile Include="Document\LineNode.cs"> + <DependentUpon>DocumentLine.cs</DependentUpon> + </Compile> + <Compile Include="Document\NewLineFinder.cs" /> + <Compile Include="Document\OffsetChangeMap.cs" /> + <Compile Include="Document\TextDocumentWeakEventManager.cs"> + <DependentUpon>TextDocument.cs</DependentUpon> + </Compile> + <Compile Include="Document\TextSegmentCollection.cs" /> + <Compile Include="Document\TextAnchor.cs" /> + <Compile Include="Document\TextAnchorNode.cs"> + <DependentUpon>TextAnchor.cs</DependentUpon> + </Compile> + <Compile Include="Document\TextAnchorTree.cs"> + <DependentUpon>TextAnchor.cs</DependentUpon> + </Compile> + <Compile Include="Document\TextLocation.cs" /> + <Compile Include="Document\TextSegment.cs" /> + <Compile Include="Document\TextUtilities.cs" /> + <Compile Include="Document\UndoOperationGroup.cs"> + <DependentUpon>UndoStack.cs</DependentUpon> + </Compile> + <Compile Include="Document\UndoStack.cs"> + </Compile> + <Compile Include="Document\WeakLineTracker.cs"> + <DependentUpon>ILineTracker.cs</DependentUpon> + </Compile> + <Compile Include="Editing\AbstractMargin.cs" /> + <Compile Include="Editing\Caret.cs" /> + <Compile Include="Editing\CaretLayer.cs"> + </Compile> + <Compile Include="Editing\CaretNavigationCommandHandler.cs"> + </Compile> + <Compile Include="Editing\CaretWeakEventHandler.cs" /> + <Compile Include="Editing\DottedLineMargin.cs" /> + <Compile Include="Editing\DragDropException.cs" /> + <Compile Include="Editing\EditingCommandHandler.cs" /> + <Compile Include="Editing\EmptySelection.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\ImeNativeWrapper.cs" /> + <Compile Include="Editing\SelectionSegment.cs" /> + <Compile Include="Editing\ImeSupport.cs" /> + <Compile Include="Folding\AbstractFoldingStrategy.cs" /> + <Compile Include="Folding\BraceFoldingStrategy.cs" /> + <Compile Include="Folding\FoldingElementGenerator.cs" /> + <Compile Include="Folding\FoldingManager.cs" /> + <Compile Include="Folding\FoldingMargin.cs" /> + <Compile Include="Folding\FoldingMarginMarker.cs" /> + <Compile Include="Folding\FoldingSection.cs" /> + <Compile Include="Editing\IReadOnlySectionProvider.cs" /> + <Compile Include="Editing\LineNumberMargin.cs" /> + <Compile Include="Editing\NoReadOnlySections.cs"> + <DependentUpon>IReadOnlySectionProvider.cs</DependentUpon> + </Compile> + <Compile Include="Editing\RectangleSelection.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\Selection.cs" /> + <Compile Include="Editing\SelectionColorizer.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\SelectionLayer.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\SelectionMouseHandler.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\SimpleSelection.cs"> + <DependentUpon>Selection.cs</DependentUpon> + </Compile> + <Compile Include="Editing\TextArea.cs" /> + <Compile Include="Editing\TextAreaDefaultInputHandlers.cs" /> + <Compile Include="Editing\TextAreaInputHandler.cs" /> + <Compile Include="Editing\TextSegmentReadOnlySectionProvider.cs"> + <DependentUpon>IReadOnlySectionProvider.cs</DependentUpon> + </Compile> + <Compile Include="Folding\NewFolding.cs" /> + <Compile Include="Folding\XmlFoldingStrategy.cs" /> + <Compile Include="Highlighting\DocumentHighlighter.cs" /> + <Compile Include="Highlighting\HighlightedInlineBuilder.cs" /> + <Compile Include="Highlighting\HighlightedLine.cs" /> + <Compile Include="Highlighting\HighlightedSection.cs" /> + <Compile Include="Highlighting\HighlightingBrush.cs" /> + <Compile Include="Highlighting\HighlightingColor.cs" /> + <Compile Include="Highlighting\HighlightingColorizer.cs" /> + <Compile Include="Highlighting\HighlightingDefinitionInvalidException.cs" /> + <Compile Include="Highlighting\HighlightingDefinitionTypeConverter.cs" /> + <Compile Include="Highlighting\HighlightingManager.cs" /> + <Compile Include="Highlighting\HtmlClipboard.cs" /> + <Compile Include="Highlighting\IHighlighter.cs" /> + <Compile Include="Highlighting\IHighlightingDefinition.cs" /> + <Compile Include="Highlighting\HighlightingRule.cs" /> + <Compile Include="Highlighting\OffsetColorizer.cs" /> + <Compile Include="Highlighting\Resources\Resources.cs" /> + <Compile Include="Highlighting\HighlightingRuleSet.cs" /> + <Compile Include="Highlighting\HighlightingSpan.cs" /> + <Compile Include="Highlighting\IHighlightingDefinitionReferenceResolver.cs"> + </Compile> + <Compile Include="Highlighting\Xshd\HighlightingLoader.cs" /> + <Compile Include="Highlighting\Xshd\IXshdVisitor.cs" /> + <Compile Include="Highlighting\Xshd\SaveXshdVisitor.cs" /> + <Compile Include="Highlighting\Xshd\V1Loader.cs" /> + <Compile Include="Highlighting\Xshd\V2Loader.cs" /> + <Compile Include="Highlighting\Xshd\XmlHighlightingDefinition.cs" /> + <Compile Include="Highlighting\Xshd\XshdColor.cs" /> + <Compile Include="Highlighting\Xshd\XshdImport.cs" /> + <Compile Include="Highlighting\Xshd\XshdProperty.cs" /> + <Compile Include="Highlighting\Xshd\XshdReference.cs" /> + <Compile Include="Highlighting\Xshd\XshdElement.cs" /> + <Compile Include="Highlighting\Xshd\XshdKeywords.cs" /> + <Compile Include="Highlighting\Xshd\XshdRule.cs" /> + <Compile Include="Highlighting\Xshd\XshdRuleSet.cs" /> + <Compile Include="Highlighting\Xshd\XshdSpan.cs" /> + <Compile Include="Highlighting\Xshd\XshdSyntaxDefinition.cs" /> + <Compile Include="Indentation\CSharp\CSharpIndentationHelper.cs" /> + <Compile Include="Indentation\CSharp\IndentationReformatter.cs" /> + <Compile Include="Indentation\CSharp\CSharpIndentationStrategy.cs" /> + <Compile Include="Indentation\CSharp\DocumentAccessor.cs" /> + <Compile Include="Indentation\DefaultIndentationStrategy.cs" /> + <Compile Include="Indentation\IIndentationStrategy.cs" /> + <Compile Include="Intellisense\KnownTypeConstructor.cs" /> + <Compile Include="Intellisense\KnownTypeEvent.cs" /> + <Compile Include="Intellisense\KnownTypeField.cs" /> + <Compile Include="Intellisense\KnownTypeMember.cs" /> + <Compile Include="Intellisense\KnownTypeMethodParameter.cs" /> + <Compile Include="Intellisense\KnownTypeMethod.cs" /> + <Compile Include="Intellisense\KnownTypeProperty.cs" /> + <Compile Include="Intellisense\ClassCompletionItem.cs" /> + <Compile Include="Intellisense\MethodCompletionItem.cs" /> + <Compile Include="Intellisense\MethodCompletionItemPopup.cs" /> + <Compile Include="Intellisense\NamespaceCompletionItem.cs" /> + <Compile Include="Intellisense\NamespaceCompletionItemPopup.cs" /> + <Compile Include="Intellisense\PropertyCompletionItem.cs" /> + <Compile Include="Intellisense\PropertyCompletionItemPopup.cs" /> + <Compile Include="Intellisense\SnippetCompletionItem.cs" /> + <Compile Include="Intellisense\StructCompletionItem.cs" /> + <Compile Include="Intellisense\StructCompletionItemPopup.cs" /> + <Compile Include="Intellisense\Utils.cs" /> + <Compile Include="Popups\MethodDescription.cs" /> + <Compile Include="Popups\MethodPopup.cs" /> + <Compile Include="Popups\ParameterDescription.cs" /> + <Compile Include="Rendering\BackgroundGeometryBuilder.cs"> + <DependentUpon>IBackgroundRenderer.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\CollapsedLineSection.cs"> + <DependentUpon>HeightTree.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\ColorizingTransformer.cs"> + <DependentUpon>IVisualLineTransformer.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\ColumnRulerRenderer.cs" /> + <Compile Include="Rendering\DefaultTextRunTypographyProperties.cs" /> + <Compile Include="Rendering\DocumentColorizingTransformer.cs"> + <DependentUpon>IVisualLineTransformer.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\FormattedTextElement.cs" /> + <Compile Include="Rendering\GlobalTextRunProperties.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\HeightTree.cs" /> + <Compile Include="Rendering\HeightTreeLineNode.cs"> + <DependentUpon>HeightTree.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\HeightTreeNode.cs"> + <DependentUpon>HeightTree.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\IBackgroundRenderer.cs" /> + <Compile Include="Rendering\InlineObjectRun.cs" /> + <Compile Include="Rendering\ITextRunConstructionContext.cs"> + <DependentUpon>VisualLineElementGenerator.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\ITextViewConnect.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\IVisualLineTransformer.cs" /> + <Compile Include="Rendering\Layer.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\LayerPosition.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\LinkElementGenerator.cs" /> + <Compile Include="Rendering\MouseHoverLogic.cs" /> + <Compile Include="Rendering\SimpleTextSource.cs"> + <DependentUpon>FormattedTextElement.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\SingleCharacterElementGenerator.cs" /> + <Compile Include="Rendering\TextLayer.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\TextView.cs" /> + <Compile Include="Rendering\TextViewCachedElements.cs" /> + <Compile Include="Rendering\TextViewWeakEventManager.cs"> + <DependentUpon>TextView.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\VisualLine.cs" /> + <Compile Include="Rendering\VisualLineConstructionStartEventArgs.cs" /> + <Compile Include="Rendering\VisualLineElement.cs" /> + <Compile Include="Rendering\VisualLineElementGenerator.cs" /> + <Compile Include="Rendering\VisualLineElementTextRunProperties.cs"> + <DependentUpon>VisualLine.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\VisualLineLinkText.cs" /> + <Compile Include="Rendering\VisualLinesInvalidException.cs" /> + <Compile Include="Rendering\VisualLineText.cs" /> + <Compile Include="Rendering\VisualLineTextParagraphProperties.cs"> + <DependentUpon>VisualLine.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\VisualLineTextSource.cs"> + <DependentUpon>VisualLineElementGenerator.cs</DependentUpon> + </Compile> + <Compile Include="Rendering\VisualYPosition.cs"> + <DependentUpon>VisualLine.cs</DependentUpon> + </Compile> + <Compile Include="ScriptEditor.cs" /> + <Compile Include="Search\Localization.cs" /> + <Compile Include="Search\RegexSearchStrategy.cs" /> + <Compile Include="Search\DropDownButton.cs" /> + <Compile Include="Search\ISearchStrategy.cs" /> + <Compile Include="Search\SearchCommands.cs" /> + <Compile Include="Search\SearchResultBackgroundRenderer.cs" /> + <Compile Include="Search\SearchPanel.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="Search\SearchStrategyFactory.cs" /> + <Compile Include="Snippets\IActiveElement.cs" /> + <Compile Include="Snippets\SnippetAnchorElement.cs" /> + <Compile Include="Snippets\SnippetEventArgs.cs" /> + <Compile Include="Snippets\SnippetInputHandler.cs" /> + <Compile Include="Snippets\Snippet.cs" /> + <Compile Include="Snippets\SnippetBoundElement.cs" /> + <Compile Include="Snippets\SnippetCaretElement.cs" /> + <Compile Include="Snippets\SnippetContainerElement.cs" /> + <Compile Include="Snippets\SnippetElement.cs" /> + <Compile Include="Snippets\InsertionContext.cs" /> + <Compile Include="Snippets\SnippetReplaceableTextElement.cs" /> + <Compile Include="Snippets\SnippetSelectionElement.cs" /> + <Compile Include="Snippets\SnippetTextElement.cs" /> + <Compile Include="TextEditor.cs" /> + <Compile Include="TextEditorAutomationPeer.cs" /> + <Compile Include="TextEditorComponent.cs"> + </Compile> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Document\DocumentChangeEventArgs.cs" /> + <Compile Include="Document\GapTextBuffer.cs"> + <DependentUpon>TextDocument.cs</DependentUpon> + </Compile> + <Compile Include="Document\LineManager.cs"> + <DependentUpon>TextDocument.cs</DependentUpon> + </Compile> + <Compile Include="Document\DocumentLine.cs" /> + <Compile Include="Document\DocumentLineTree.cs"> + <DependentUpon>DocumentLine.cs</DependentUpon> + </Compile> + <Compile Include="Document\TextDocument.cs" /> + <Compile Include="TextEditorOptions.cs" /> + <Compile Include="TextEditorWeakEventManager.cs"> + <DependentUpon>TextEditor.cs</DependentUpon> + </Compile> + <Compile Include="TextViewPosition.cs" /> + <Compile Include="Utils\Boxes.cs" /> + <Compile Include="Utils\BusyManager.cs"> + <DependentUpon>ObserveAddRemoveCollection.cs</DependentUpon> + </Compile> + <Compile Include="Utils\CharRope.cs" /> + <Compile Include="Utils\CompressingTreeList.cs" /> + <Compile Include="Utils\Constants.cs" /> + <Compile Include="Utils\DelayedEvents.cs" /> + <Compile Include="Utils\CallbackOnDispose.cs" /> + <Compile Include="Utils\Deque.cs" /> + <Compile Include="Utils\Empty.cs" /> + <Compile Include="Utils\ExtensionMethods.cs" /> + <Compile Include="Utils\FileReader.cs" /> + <Compile Include="Utils\ImmutableStack.cs" /> + <Compile Include="Utils\NullSafeCollection.cs" /> + <Compile Include="Utils\ObserveAddRemoveCollection.cs" /> + <Compile Include="Utils\PropertyChangedWeakEventManager.cs" /> + <Compile Include="Utils\Rope.cs" /> + <Compile Include="Utils\RopeNode.cs" /> + <Compile Include="Utils\RopeTextReader.cs" /> + <Compile Include="Utils\StringSegment.cs" /> + <Compile Include="Utils\TextFormatterFactory.cs" /> + <Compile Include="Utils\WeakEventManagerBase.cs" /> + <Compile Include="Utils\PixelSnapHelpers.cs" /> + <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" /> + <Compile Include="Xml\AXmlContainer.cs" /> + <Compile Include="Xml\AXmlDocument.cs" /> + <Compile Include="Xml\AXmlElement.cs" /> + <Compile Include="Xml\AXmlObject.cs" /> + <Compile Include="Xml\AXmlObjectCollection.cs" /> + <Compile Include="Xml\AXmlObjectEventArgs.cs" /> + <Compile Include="Xml\AXmlParser.cs" /> + <Compile Include="Xml\AXmlTag.cs" /> + <Compile Include="Xml\AXmlText.cs" /> + <Compile Include="Xml\CanonicalPrintAXmlVisitor.cs" /> + <Compile Include="Xml\InternalException.cs" /> + <Compile Include="Xml\TrackedSegmentCollection.cs"> + <DependentUpon>AXmlParser.cs</DependentUpon> + </Compile> + <Compile Include="Xml\ExtensionMethods.cs" /> + <Compile Include="Xml\FilteredCollection.cs" /> + <Compile Include="Xml\IAXmlVisitor.cs" /> + <Compile Include="Xml\MergedCollection.cs" /> + <Compile Include="Xml\PrettyPrintAXmlVisitor.cs" /> + <Compile Include="Xml\SyntaxError.cs" /> + <Compile Include="Xml\TagMatchingHeuristics.cs"> + <DependentUpon>AXmlParser.cs</DependentUpon> + </Compile> + <Compile Include="Xml\TagReader.cs"> + <DependentUpon>AXmlParser.cs</DependentUpon> + </Compile> + <Compile Include="Xml\TextType.cs"> + <DependentUpon>AXmlText.cs</DependentUpon> + </Compile> + <Compile Include="Xml\TokenReader.cs"> + <DependentUpon>AXmlParser.cs</DependentUpon> + </Compile> + <EmbeddedResource Include="Highlighting\Resources\ASPX.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Boo.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Coco-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\CPP-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\HTML-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Java-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\JavaScript-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Patch-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\PHP-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\Tex-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\VBNET-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\XML-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\ModeV1.xsd" /> + <EmbeddedResource Include="Highlighting\Resources\ModeV2.xsd" /> + <EmbeddedResource Include="Highlighting\Resources\CSharp-Mode.xshd" /> + <EmbeddedResource Include="Highlighting\Resources\XmlDoc.xshd" /> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Highlighting\Resources\CSS-Mode.xshd" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj"> + <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> + <Name>Tango.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Core\Tango.Scripting.Core.csproj"> + <Project>{5812E1C6-ABAA-4066-94AC-971C27B4F46A}</Project> + <Name>Tango.Scripting.Core</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting.Formatting\Tango.Scripting.Formatting.csproj"> + <Project>{8d8f06ed-7f75-4933-b0c5-829b0ff654d0}</Project> + <Name>Tango.Scripting.Formatting</Name> + </ProjectReference> + <ProjectReference Include="..\Tango.Scripting\Tango.Scripting.csproj"> + <Project>{1e938fd2-c669-4738-98c9-77f96ce4d451}</Project> + <Name>Tango.Scripting</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Highlighting\Resources\PowerShell.xshd" /> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Highlighting\Resources\MarkDown-Mode.xshd" /> + </ItemGroup> + <ItemGroup> + <None Include="app.config" /> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + <Analyzer Include="..\..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" /> + <Analyzer Include="..\..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" /> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <ItemGroup> + </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" /> + </VisualStudio> + </ProjectExtensions> + <ItemGroup> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\FontAwesome.WPF.4.7.0.9\lib\net40\FontAwesome.WPF.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\Microsoft.CodeAnalysis.CSharp.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\Microsoft.CodeAnalysis.Common.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\mscorlib.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\PresentationCore.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\PresentationFramework.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.ComponentModel.Composition.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Console.4.3.0\lib\net46\System.Console.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Core.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Data.DataSetExtensions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Data.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Drawing.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Numerics.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Windows.Forms.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Xaml.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Xml.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Xml.Linq.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Core\Debug\Tango.Core.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Scripting\Tango.Scripting.Core\bin\Debug\Tango.Scripting.Core.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Build\Scripting\Debug\Tango.Scripting.dll" /> + <ReferencePath Include="C:\DATA\Development\Tango\Software\Visual_Studio\Scripting\Tango.Scripting.Formatting\bin\Debug\Tango.Scripting.Formatting.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\UIAutomationProvider.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\UIAutomationTypes.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\WindowsBase.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Collections.Concurrent.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Collections.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ComponentModel.Annotations.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ComponentModel.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ComponentModel.EventBasedAsync.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Contracts.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Debug.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Tools.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Diagnostics.Tracing.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Dynamic.Runtime.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Globalization.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.IO.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.Expressions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.Parallel.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Linq.Queryable.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.NetworkInformation.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.Requests.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Net.WebHeaderCollection.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ObjectModel.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Emit.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Emit.ILGeneration.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Emit.Lightweight.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Extensions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Reflection.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Resources.ResourceManager.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Extensions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Handles.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.InteropServices.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.InteropServices.WindowsRuntime.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Numerics.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Serialization.Json.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Serialization.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Runtime.Serialization.Xml.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Security.Principal.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Duplex.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Http.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.NetTcp.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Primitives.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.ServiceModel.Security.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Text.Encoding.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Text.Encoding.Extensions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Text.RegularExpressions.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.Tasks.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.Tasks.Parallel.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Threading.Timer.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Xml.XDocument.dll" /> + <ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\Facades\System.Xml.XmlSerializer.dll" /> + </ItemGroup> + <ItemGroup> + <Compile Include="C:\DATA\Development\Tango\Software\Visual_Studio\Scripting\Tango.Scripting.Editors\obj\Debug\GeneratedInternalTypeHelper.g.cs" /> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs index d2fc9e02b..cd9977520 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs @@ -3,6 +3,7 @@ using System; using System.ComponentModel; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -24,1121 +25,1229 @@ using Tango.Scripting.Editors.Utils; namespace Tango.Scripting.Editors { - /// <summary> - /// The text editor control. - /// Contains a scrollable TextArea. - /// </summary> - [Localizability(LocalizationCategory.Text), ContentProperty("Text")] - public class TextEditor : Control, ITextEditorComponent, IServiceProvider, IWeakEventListener - { - #region Constructors - static TextEditor() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(TextEditor), - new FrameworkPropertyMetadata(typeof(TextEditor))); - FocusableProperty.OverrideMetadata(typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.True)); - } - - /// <summary> - /// Creates a new TextEditor instance. - /// </summary> - public TextEditor() : this(new TextArea()) - { - } - - /// <summary> - /// Creates a new TextEditor instance. - /// </summary> - protected TextEditor(TextArea textArea) - { - if (textArea == null) - throw new ArgumentNullException("textArea"); - this.textArea = textArea; - - textArea.TextView.Services.AddService(typeof(TextEditor), this); - - SetCurrentValue(OptionsProperty, textArea.Options); - SetCurrentValue(DocumentProperty, new TextDocument()); - } - - #endregion - - /// <inheritdoc/> - protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer() - { - return new TextEditorAutomationPeer(this); - } - - /// Forward focus to TextArea. - /// <inheritdoc/> - protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) - { - base.OnGotKeyboardFocus(e); - if (e.NewFocus == this) { - Keyboard.Focus(this.TextArea); - e.Handled = true; - } - } - - #region Document property - /// <summary> - /// Document property. - /// </summary> - public static readonly DependencyProperty DocumentProperty - = TextView.DocumentProperty.AddOwner( - typeof(TextEditor), new FrameworkPropertyMetadata(OnDocumentChanged)); - - /// <summary> - /// Gets/Sets the document displayed by the text editor. - /// This is a dependency property. - /// </summary> - public TextDocument Document { - get { return (TextDocument)GetValue(DocumentProperty); } - set { SetValue(DocumentProperty, value); } - } - - /// <summary> - /// Occurs when the document property has changed. - /// </summary> - public event EventHandler DocumentChanged; - - /// <summary> - /// Raises the <see cref="DocumentChanged"/> event. - /// </summary> - protected virtual void OnDocumentChanged(EventArgs e) - { - if (DocumentChanged != null) { - DocumentChanged(this, e); - } - } - - static void OnDocumentChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) - { - ((TextEditor)dp).OnDocumentChanged((TextDocument)e.OldValue, (TextDocument)e.NewValue); - } - - void OnDocumentChanged(TextDocument oldValue, TextDocument newValue) - { - if (oldValue != null) { - TextDocumentWeakEventManager.TextChanged.RemoveListener(oldValue, this); - PropertyChangedEventManager.RemoveListener(oldValue.UndoStack, this, "IsOriginalFile"); - } - textArea.Document = newValue; - if (newValue != null) { - TextDocumentWeakEventManager.TextChanged.AddListener(newValue, this); - PropertyChangedEventManager.AddListener(newValue.UndoStack, this, "IsOriginalFile"); - } - OnDocumentChanged(EventArgs.Empty); - OnTextChanged(EventArgs.Empty); - } - #endregion - - #region Options property - /// <summary> - /// Options property. - /// </summary> - public static readonly DependencyProperty OptionsProperty - = TextView.OptionsProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(OnOptionsChanged)); - - /// <summary> - /// Gets/Sets the options currently used by the text editor. - /// </summary> - public TextEditorOptions Options { - get { return (TextEditorOptions)GetValue(OptionsProperty); } - set { SetValue(OptionsProperty, value); } - } - - /// <summary> - /// Occurs when a text editor option has changed. - /// </summary> - public event PropertyChangedEventHandler OptionChanged; - - /// <summary> - /// Raises the <see cref="OptionChanged"/> event. - /// </summary> - protected virtual void OnOptionChanged(PropertyChangedEventArgs e) - { - if (OptionChanged != null) { - OptionChanged(this, e); - } - } - - static void OnOptionsChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) - { - ((TextEditor)dp).OnOptionsChanged((TextEditorOptions)e.OldValue, (TextEditorOptions)e.NewValue); - } - - void OnOptionsChanged(TextEditorOptions oldValue, TextEditorOptions newValue) - { - if (oldValue != null) { - PropertyChangedWeakEventManager.RemoveListener(oldValue, this); - } - textArea.Options = newValue; - if (newValue != null) { - PropertyChangedWeakEventManager.AddListener(newValue, this); - } - OnOptionChanged(new PropertyChangedEventArgs(null)); - } - - /// <inheritdoc cref="IWeakEventListener.ReceiveWeakEvent"/> - protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) - { - if (managerType == typeof(PropertyChangedWeakEventManager)) { - OnOptionChanged((PropertyChangedEventArgs)e); - return true; - } else if (managerType == typeof(TextDocumentWeakEventManager.TextChanged)) { - OnTextChanged(e); - return true; - } else if (managerType == typeof(PropertyChangedEventManager)) { - return HandleIsOriginalChanged((PropertyChangedEventArgs)e); - } - return false; - } - - bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) - { - return ReceiveWeakEvent(managerType, sender, e); - } - #endregion - - #region Text property - /// <summary> - /// Gets/Sets the text of the current document. - /// </summary> - [Localizability(LocalizationCategory.Text), DefaultValue("")] - public string Text { - get { - TextDocument document = this.Document; - return document != null ? document.Text : string.Empty; - } - set { - TextDocument document = GetDocument(); - document.Text = value ?? string.Empty; - // after replacing the full text, the caret is positioned at the end of the document - // - reset it to the beginning. - this.CaretOffset = 0; - document.UndoStack.ClearAll(); - } - } - - TextDocument GetDocument() - { - TextDocument document = this.Document; - if (document == null) - throw ThrowUtil.NoDocumentAssigned(); - return document; - } - - /// <summary> - /// Occurs when the Text property changes. - /// </summary> - public event EventHandler TextChanged; - - /// <summary> - /// Raises the <see cref="TextChanged"/> event. - /// </summary> - protected virtual void OnTextChanged(EventArgs e) - { - if (TextChanged != null) { - TextChanged(this, e); - } - } - #endregion - - #region TextArea / ScrollViewer properties - readonly TextArea textArea; - ScrollViewer scrollViewer; - - /// <summary> - /// Is called after the template was applied. - /// </summary> - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - scrollViewer = (ScrollViewer)Template.FindName("PART_ScrollViewer", this); - } - - /// <summary> - /// Gets the text area. - /// </summary> - public TextArea TextArea { - get { - return textArea; - } - } - - /// <summary> - /// Gets the scroll viewer used by the text editor. - /// This property can return null if the template has not been applied / does not contain a scroll viewer. - /// </summary> - internal ScrollViewer ScrollViewer { - get { return scrollViewer; } - } - - bool CanExecute(RoutedUICommand command) - { - TextArea textArea = this.TextArea; - if (textArea == null) - return false; - else - return command.CanExecute(null, textArea); - } - - void Execute(RoutedUICommand command) - { - TextArea textArea = this.TextArea; - if (textArea != null) - command.Execute(null, textArea); - } - #endregion - - #region Syntax highlighting - /// <summary> - /// The <see cref="SyntaxHighlighting"/> property. - /// </summary> - public static readonly DependencyProperty SyntaxHighlightingProperty = - DependencyProperty.Register("SyntaxHighlighting", typeof(IHighlightingDefinition), typeof(TextEditor), - new FrameworkPropertyMetadata(OnSyntaxHighlightingChanged)); - - - /// <summary> - /// Gets/sets the syntax highlighting definition used to colorize the text. - /// </summary> - public IHighlightingDefinition SyntaxHighlighting { - get { return (IHighlightingDefinition)GetValue(SyntaxHighlightingProperty); } - set { SetValue(SyntaxHighlightingProperty, value); } - } - - IVisualLineTransformer colorizer; - - static void OnSyntaxHighlightingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((TextEditor)d).OnSyntaxHighlightingChanged(e.NewValue as IHighlightingDefinition); - } - - void OnSyntaxHighlightingChanged(IHighlightingDefinition newValue) - { - if (colorizer != null) { - this.TextArea.TextView.LineTransformers.Remove(colorizer); - colorizer = null; - } - if (newValue != null) { - colorizer = CreateColorizer(newValue); - this.TextArea.TextView.LineTransformers.Insert(0, colorizer); - } - } - - /// <summary> - /// Creates the highlighting colorizer for the specified highlighting definition. - /// Allows derived classes to provide custom colorizer implementations for special highlighting definitions. - /// </summary> - /// <returns></returns> - protected virtual IVisualLineTransformer CreateColorizer(IHighlightingDefinition highlightingDefinition) - { - if (highlightingDefinition == null) - throw new ArgumentNullException("highlightingDefinition"); - return new HighlightingColorizer(highlightingDefinition.MainRuleSet); - } - #endregion - - #region WordWrap - /// <summary> - /// Word wrap dependency property. - /// </summary> - public static readonly DependencyProperty WordWrapProperty = - DependencyProperty.Register("WordWrap", typeof(bool), typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.False)); - - /// <summary> - /// Specifies whether the text editor uses word wrapping. - /// </summary> - /// <remarks> - /// Setting WordWrap=true has the same effect as setting HorizontalScrollBarVisibility=Disabled and will override the - /// HorizontalScrollBarVisibility setting. - /// </remarks> - public bool WordWrap { - get { return (bool)GetValue(WordWrapProperty); } - set { SetValue(WordWrapProperty, Boxes.Box(value)); } - } - #endregion - - #region IsReadOnly - /// <summary> - /// IsReadOnly dependency property. - /// </summary> - public static readonly DependencyProperty IsReadOnlyProperty = - DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.False, OnIsReadOnlyChanged)); - - /// <summary> - /// Specifies whether the user can change the text editor content. - /// Setting this property will replace the - /// <see cref="Editing.TextArea.ReadOnlySectionProvider">TextArea.ReadOnlySectionProvider</see>. - /// </summary> - public bool IsReadOnly { - get { return (bool)GetValue(IsReadOnlyProperty); } - set { SetValue(IsReadOnlyProperty, Boxes.Box(value)); } - } - - static void OnIsReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TextEditor editor = d as TextEditor; - if (editor != null) { - if ((bool)e.NewValue) - editor.TextArea.ReadOnlySectionProvider = ReadOnlyDocument.Instance; - else - editor.TextArea.ReadOnlySectionProvider = NoReadOnlySections.Instance; - - TextEditorAutomationPeer peer = TextEditorAutomationPeer.FromElement(editor) as TextEditorAutomationPeer; - if (peer != null) { - peer.RaiseIsReadOnlyChanged((bool)e.OldValue, (bool)e.NewValue); - } - } - } - #endregion - - #region IsModified - /// <summary> - /// Dependency property for <see cref="IsModified"/> - /// </summary> - public static readonly DependencyProperty IsModifiedProperty = - DependencyProperty.Register("IsModified", typeof(bool), typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.False, OnIsModifiedChanged)); - - /// <summary> - /// Gets/Sets the 'modified' flag. - /// </summary> - public bool IsModified { - get { return (bool)GetValue(IsModifiedProperty); } - set { SetValue(IsModifiedProperty, Boxes.Box(value)); } - } - - static void OnIsModifiedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TextEditor editor = d as TextEditor; - if (editor != null) { - TextDocument document = editor.Document; - if (document != null) { - UndoStack undoStack = document.UndoStack; - if ((bool)e.NewValue) { - if (undoStack.IsOriginalFile) - undoStack.DiscardOriginalFileMarker(); - } else { - undoStack.MarkAsOriginalFile(); - } - } - } - } - - bool HandleIsOriginalChanged(PropertyChangedEventArgs e) - { - if (e.PropertyName == "IsOriginalFile") { - TextDocument document = this.Document; - if (document != null) { - SetCurrentValue(IsModifiedProperty, Boxes.Box(!document.UndoStack.IsOriginalFile)); - } - return true; - } else { - return false; - } - } - #endregion - - #region ShowLineNumbers - /// <summary> - /// ShowLineNumbers dependency property. - /// </summary> - public static readonly DependencyProperty ShowLineNumbersProperty = - DependencyProperty.Register("ShowLineNumbers", typeof(bool), typeof(TextEditor), - new FrameworkPropertyMetadata(Boxes.False, OnShowLineNumbersChanged)); - - /// <summary> - /// Specifies whether line numbers are shown on the left to the text view. - /// </summary> - public bool ShowLineNumbers { - get { return (bool)GetValue(ShowLineNumbersProperty); } - set { SetValue(ShowLineNumbersProperty, Boxes.Box(value)); } - } - - static void OnShowLineNumbersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TextEditor editor = (TextEditor)d; - var leftMargins = editor.TextArea.LeftMargins; - if ((bool)e.NewValue) { - LineNumberMargin lineNumbers = new LineNumberMargin(); - Line line = (Line)DottedLineMargin.Create(); - leftMargins.Insert(0, lineNumbers); - leftMargins.Insert(1, line); - var lineNumbersForeground = new Binding("LineNumbersForeground") { Source = editor }; - line.SetBinding(Line.StrokeProperty, lineNumbersForeground); - lineNumbers.SetBinding(Control.ForegroundProperty, lineNumbersForeground); - } else { - for (int i = 0; i < leftMargins.Count; i++) { - if (leftMargins[i] is LineNumberMargin) { - leftMargins.RemoveAt(i); - if (i < leftMargins.Count && DottedLineMargin.IsDottedLineMargin(leftMargins[i])) { - leftMargins.RemoveAt(i); - } - break; - } - } - } - } - #endregion - - #region LineNumbersForeground - /// <summary> - /// LineNumbersForeground dependency property. - /// </summary> - public static readonly DependencyProperty LineNumbersForegroundProperty = - DependencyProperty.Register("LineNumbersForeground", typeof(Brush), typeof(TextEditor), - new FrameworkPropertyMetadata(Brushes.Gray, OnLineNumbersForegroundChanged)); - - /// <summary> - /// Gets/sets the Brush used for displaying the foreground color of line numbers. - /// </summary> - public Brush LineNumbersForeground { - get { return (Brush)GetValue(LineNumbersForegroundProperty); } - set { SetValue(LineNumbersForegroundProperty, value); } - } - - static void OnLineNumbersForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TextEditor editor = (TextEditor)d; - var lineNumberMargin = editor.TextArea.LeftMargins.FirstOrDefault(margin => margin is LineNumberMargin) as LineNumberMargin;; - - if (lineNumberMargin != null) { - lineNumberMargin.SetValue(Control.ForegroundProperty, e.NewValue); - } - } - #endregion - - #region TextBoxBase-like methods - /// <summary> - /// Appends text to the end of the document. - /// </summary> - public void AppendText(string textData) - { - var document = GetDocument(); - document.Insert(document.TextLength, textData); - } - - /// <summary> - /// Begins a group of document changes. - /// </summary> - public void BeginChange() - { - GetDocument().BeginUpdate(); - } - - /// <summary> - /// Copies the current selection to the clipboard. - /// </summary> - public void Copy() - { - Execute(ApplicationCommands.Copy); - } - - /// <summary> - /// Removes the current selection and copies it to the clipboard. - /// </summary> - public void Cut() - { - Execute(ApplicationCommands.Cut); - } - - /// <summary> - /// Begins a group of document changes and returns an object that ends the group of document - /// changes when it is disposed. - /// </summary> - public IDisposable DeclareChangeBlock() - { - return GetDocument().RunUpdate(); - } - - /// <summary> - /// Ends the current group of document changes. - /// </summary> - public void EndChange() - { - GetDocument().EndUpdate(); - } - - /// <summary> - /// Scrolls one line down. - /// </summary> - public void LineDown() - { - if (scrollViewer != null) - scrollViewer.LineDown(); - } - - /// <summary> - /// Scrolls to the left. - /// </summary> - public void LineLeft() - { - if (scrollViewer != null) - scrollViewer.LineLeft(); - } - - /// <summary> - /// Scrolls to the right. - /// </summary> - public void LineRight() - { - if (scrollViewer != null) - scrollViewer.LineRight(); - } - - /// <summary> - /// Scrolls one line up. - /// </summary> - public void LineUp() - { - if (scrollViewer != null) - scrollViewer.LineUp(); - } - - /// <summary> - /// Scrolls one page down. - /// </summary> - public void PageDown() - { - if (scrollViewer != null) - scrollViewer.PageDown(); - } - - /// <summary> - /// Scrolls one page up. - /// </summary> - public void PageUp() - { - if (scrollViewer != null) - scrollViewer.PageUp(); - } - - /// <summary> - /// Scrolls one page left. - /// </summary> - public void PageLeft() - { - if (scrollViewer != null) - scrollViewer.PageLeft(); - } - - /// <summary> - /// Scrolls one page right. - /// </summary> - public void PageRight() - { - if (scrollViewer != null) - scrollViewer.PageRight(); - } - - /// <summary> - /// Pastes the clipboard content. - /// </summary> - public void Paste() - { - Execute(ApplicationCommands.Paste); - } - - /// <summary> - /// Redoes the most recent undone command. - /// </summary> - /// <returns>True is the redo operation was successful, false is the redo stack is empty.</returns> - public bool Redo() - { - if (CanExecute(ApplicationCommands.Redo)) { - Execute(ApplicationCommands.Redo); - return true; - } - return false; - } - - /// <summary> - /// Scrolls to the end of the document. - /// </summary> - public void ScrollToEnd() - { - ApplyTemplate(); // ensure scrollViewer is created - if (scrollViewer != null) - scrollViewer.ScrollToEnd(); - } - - /// <summary> - /// Scrolls to the start of the document. - /// </summary> - public void ScrollToHome() - { - ApplyTemplate(); // ensure scrollViewer is created - if (scrollViewer != null) - scrollViewer.ScrollToHome(); - } - - /// <summary> - /// Scrolls to the specified position in the document. - /// </summary> - public void ScrollToHorizontalOffset(double offset) - { - ApplyTemplate(); // ensure scrollViewer is created - if (scrollViewer != null) - scrollViewer.ScrollToHorizontalOffset(offset); - } - - /// <summary> - /// Scrolls to the specified position in the document. - /// </summary> - public void ScrollToVerticalOffset(double offset) - { - ApplyTemplate(); // ensure scrollViewer is created - if (scrollViewer != null) - scrollViewer.ScrollToVerticalOffset(offset); - } - - /// <summary> - /// Selects the entire text. - /// </summary> - public void SelectAll() - { - Execute(ApplicationCommands.SelectAll); - } - - /// <summary> - /// Undoes the most recent command. - /// </summary> - /// <returns>True is the undo operation was successful, false is the undo stack is empty.</returns> - public bool Undo() - { - if (CanExecute(ApplicationCommands.Undo)) { - Execute(ApplicationCommands.Undo); - return true; - } - return false; - } - - /// <summary> - /// Gets if the most recent undone command can be redone. - /// </summary> - public bool CanRedo { - get { return CanExecute(ApplicationCommands.Redo); } - } - - /// <summary> - /// Gets if the most recent command can be undone. - /// </summary> - public bool CanUndo { - get { return CanExecute(ApplicationCommands.Undo); } - } - - /// <summary> - /// Gets the vertical size of the document. - /// </summary> - public double ExtentHeight { - get { - return scrollViewer != null ? scrollViewer.ExtentHeight : 0; - } - } - - /// <summary> - /// Gets the horizontal size of the current document region. - /// </summary> - public double ExtentWidth { - get { - return scrollViewer != null ? scrollViewer.ExtentWidth : 0; - } - } - - /// <summary> - /// Gets the horizontal size of the viewport. - /// </summary> - public double ViewportHeight { - get { - return scrollViewer != null ? scrollViewer.ViewportHeight : 0; - } - } - - /// <summary> - /// Gets the horizontal size of the viewport. - /// </summary> - public double ViewportWidth { - get { - return scrollViewer != null ? scrollViewer.ViewportWidth : 0; - } - } - - /// <summary> - /// Gets the vertical scroll position. - /// </summary> - public double VerticalOffset { - get { - return scrollViewer != null ? scrollViewer.VerticalOffset : 0; - } - } - - /// <summary> - /// Gets the horizontal scroll position. - /// </summary> - public double HorizontalOffset { - get { - return scrollViewer != null ? scrollViewer.HorizontalOffset : 0; - } - } - #endregion - - #region TextBox methods - /// <summary> - /// Gets/Sets the selected text. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public string SelectedText { - get { - TextArea textArea = this.TextArea; - // We'll get the text from the whole surrounding segment. - // This is done to ensure that SelectedText.Length == SelectionLength. - if (textArea != null && textArea.Document != null && !textArea.Selection.IsEmpty) - return textArea.Document.GetText(textArea.Selection.SurroundingSegment); - else - return string.Empty; - } - set { - if (value == null) - throw new ArgumentNullException("value"); - TextArea textArea = this.TextArea; - if (textArea != null && textArea.Document != null) { - int offset = this.SelectionStart; - int length = this.SelectionLength; - textArea.Document.Replace(offset, length, value); - // keep inserted text selected - textArea.Selection = SimpleSelection.Create(textArea, offset, offset + value.Length); - } - } - } - - /// <summary> - /// Gets/sets the caret position. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int CaretOffset { - get { - TextArea textArea = this.TextArea; - if (textArea != null) - return textArea.Caret.Offset; - else - return 0; - } - set { - TextArea textArea = this.TextArea; - if (textArea != null) - textArea.Caret.Offset = value; - } - } - - /// <summary> - /// Gets/sets the start position of the selection. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int SelectionStart { - get { - TextArea textArea = this.TextArea; - if (textArea != null) { - if (textArea.Selection.IsEmpty) - return textArea.Caret.Offset; - else - return textArea.Selection.SurroundingSegment.Offset; - } else { - return 0; - } - } - set { - Select(value, SelectionLength); - } - } - - /// <summary> - /// Gets/sets the length of the selection. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int SelectionLength { - get { - TextArea textArea = this.TextArea; - if (textArea != null && !textArea.Selection.IsEmpty) - return textArea.Selection.SurroundingSegment.Length; - else - return 0; - } - set { - Select(SelectionStart, value); - } - } - - /// <summary> - /// Selects the specified text section. - /// </summary> - public void Select(int start, int length) - { - int documentLength = Document != null ? Document.TextLength : 0; - if (start < 0 || start > documentLength) - throw new ArgumentOutOfRangeException("start", start, "Value must be between 0 and " + documentLength); - if (length < 0 || start + length > documentLength) - throw new ArgumentOutOfRangeException("length", length, "Value must be between 0 and " + (documentLength - length)); - textArea.Selection = SimpleSelection.Create(textArea, start, start + length); - textArea.Caret.Offset = start + length; - } - - /// <summary> - /// Gets the number of lines in the document. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int LineCount { - get { - TextDocument document = this.Document; - if (document != null) - return document.LineCount; - else - return 1; - } - } - - /// <summary> - /// Clears the text. - /// </summary> - public void Clear() - { - this.Text = string.Empty; - } - #endregion - - #region Loading from stream - /// <summary> - /// Loads the text from the stream, auto-detecting the encoding. - /// </summary> - /// <remarks> - /// This method sets <see cref="IsModified"/> to false. - /// </remarks> - public void Load(Stream stream) - { - using (StreamReader reader = FileReader.OpenStream(stream, this.Encoding ?? Encoding.UTF8)) { - this.Text = reader.ReadToEnd(); - this.Encoding = reader.CurrentEncoding; // assign encoding after ReadToEnd() so that the StreamReader can autodetect the encoding - } - this.IsModified = false; - } - - /// <summary> - /// Loads the text from the stream, auto-detecting the encoding. - /// </summary> - public void Load(string fileName) - { - if (fileName == null) - throw new ArgumentNullException("fileName"); - using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { - Load(fs); - } - } - - /// <summary> - /// Gets/sets the encoding used when the file is saved. - /// </summary> - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Encoding Encoding { get; set; } - - /// <summary> - /// Saves the text to the stream. - /// </summary> - /// <remarks> - /// This method sets <see cref="IsModified"/> to false. - /// </remarks> - public void Save(Stream stream) - { - if (stream == null) - throw new ArgumentNullException("stream"); - StreamWriter writer = new StreamWriter(stream, this.Encoding ?? Encoding.UTF8); - writer.Write(this.Text); - writer.Flush(); - // do not close the stream - this.IsModified = false; - } - - /// <summary> - /// Saves the text to the file. - /// </summary> - public void Save(string fileName) - { - if (fileName == null) - throw new ArgumentNullException("fileName"); - using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) { - Save(fs); - } - } - #endregion - - #region MouseHover events - /// <summary> - /// The PreviewMouseHover event. - /// </summary> - public static readonly RoutedEvent PreviewMouseHoverEvent = - TextView.PreviewMouseHoverEvent.AddOwner(typeof(TextEditor)); - - /// <summary> - /// The MouseHover event. - /// </summary> - public static readonly RoutedEvent MouseHoverEvent = - TextView.MouseHoverEvent.AddOwner(typeof(TextEditor)); - - - /// <summary> - /// The PreviewMouseHoverStopped event. - /// </summary> - public static readonly RoutedEvent PreviewMouseHoverStoppedEvent = - TextView.PreviewMouseHoverStoppedEvent.AddOwner(typeof(TextEditor)); - - /// <summary> - /// The MouseHoverStopped event. - /// </summary> - public static readonly RoutedEvent MouseHoverStoppedEvent = - TextView.MouseHoverStoppedEvent.AddOwner(typeof(TextEditor)); - - - /// <summary> - /// Occurs when the mouse has hovered over a fixed location for some time. - /// </summary> - public event MouseEventHandler PreviewMouseHover { - add { AddHandler(PreviewMouseHoverEvent, value); } - remove { RemoveHandler(PreviewMouseHoverEvent, value); } - } - - /// <summary> - /// Occurs when the mouse has hovered over a fixed location for some time. - /// </summary> - public event MouseEventHandler MouseHover { - add { AddHandler(MouseHoverEvent, value); } - remove { RemoveHandler(MouseHoverEvent, value); } - } - - /// <summary> - /// Occurs when the mouse had previously hovered but now started moving again. - /// </summary> - public event MouseEventHandler PreviewMouseHoverStopped { - add { AddHandler(PreviewMouseHoverStoppedEvent, value); } - remove { RemoveHandler(PreviewMouseHoverStoppedEvent, value); } - } - - /// <summary> - /// Occurs when the mouse had previously hovered but now started moving again. - /// </summary> - public event MouseEventHandler MouseHoverStopped { - add { AddHandler(MouseHoverStoppedEvent, value); } - remove { RemoveHandler(MouseHoverStoppedEvent, value); } - } - #endregion - - #region ScrollBarVisibility - /// <summary> - /// Dependency property for <see cref="HorizontalScrollBarVisibility"/> - /// </summary> - public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = ScrollViewer.HorizontalScrollBarVisibilityProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(ScrollBarVisibility.Visible)); - - /// <summary> - /// Gets/Sets the horizontal scroll bar visibility. - /// </summary> - public ScrollBarVisibility HorizontalScrollBarVisibility { - get { return (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty); } - set { SetValue(HorizontalScrollBarVisibilityProperty, value); } - } - - /// <summary> - /// Dependency property for <see cref="VerticalScrollBarVisibility"/> - /// </summary> - public static readonly DependencyProperty VerticalScrollBarVisibilityProperty = ScrollViewer.VerticalScrollBarVisibilityProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(ScrollBarVisibility.Visible)); - - /// <summary> - /// Gets/Sets the vertical scroll bar visibility. - /// </summary> - public ScrollBarVisibility VerticalScrollBarVisibility { - get { return (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty); } - set { SetValue(VerticalScrollBarVisibilityProperty, value); } - } - #endregion - - object IServiceProvider.GetService(Type serviceType) - { - return textArea.GetService(serviceType); - } - - /// <summary> - /// Gets the text view position from a point inside the editor. - /// </summary> - /// <param name="point">The position, relative to top left - /// corner of TextEditor control</param> - /// <returns>The text view position, or null if the point is outside the document.</returns> - public TextViewPosition? GetPositionFromPoint(Point point) - { - if (this.Document == null) - return null; - TextView textView = this.TextArea.TextView; - return textView.GetPosition(TranslatePoint(point, textView) + textView.ScrollOffset); - } - - /// <summary> - /// Scrolls to the specified line. - /// This method requires that the TextEditor was already assigned a size (WPF layout must have run prior). - /// </summary> - public void ScrollToLine(int line) - { - ScrollTo(line, -1); - } - - /// <summary> - /// Scrolls to the specified line/column. - /// This method requires that the TextEditor was already assigned a size (WPF layout must have run prior). - /// </summary> - public void ScrollTo(int line, int column) - { - const double MinimumScrollPercentage = 0.3; - - TextView textView = textArea.TextView; - TextDocument document = textView.Document; - if (scrollViewer != null && document != null) { - if (line < 1) - line = 1; - if (line > document.LineCount) - line = document.LineCount; - - IScrollInfo scrollInfo = textView; - if (!scrollInfo.CanHorizontallyScroll) { - // Word wrap is enabled. Ensure that we have up-to-date info about line height so that we scroll - // to the correct position. - // This avoids that the user has to repeat the ScrollTo() call several times when there are very long lines. - VisualLine vl = textView.GetOrConstructVisualLine(document.GetLineByNumber(line)); - double remainingHeight = scrollViewer.ViewportHeight / 2; - while (remainingHeight > 0) { - DocumentLine prevLine = vl.FirstDocumentLine.PreviousLine; - if (prevLine == null) - break; - vl = textView.GetOrConstructVisualLine(prevLine); - remainingHeight -= vl.Height; - } - } - - Point p = textArea.TextView.GetVisualPosition(new TextViewPosition(line, Math.Max(1, column)), VisualYPosition.LineMiddle); - double verticalPos = p.Y - scrollViewer.ViewportHeight / 2; - if (Math.Abs(verticalPos - scrollViewer.VerticalOffset) > MinimumScrollPercentage * scrollViewer.ViewportHeight) { - scrollViewer.ScrollToVerticalOffset(Math.Max(0, verticalPos)); - } - if (column > 0) { - if (p.X > scrollViewer.ViewportWidth - Caret.MinimumDistanceToViewBorder * 2) { - double horizontalPos = Math.Max(0, p.X - scrollViewer.ViewportWidth / 2); - if (Math.Abs(horizontalPos - scrollViewer.HorizontalOffset) > MinimumScrollPercentage * scrollViewer.ViewportWidth) { - scrollViewer.ScrollToHorizontalOffset(horizontalPos); - } - } else { - scrollViewer.ScrollToHorizontalOffset(0); - } - } - } - } - } + /// <summary> + /// The text editor control. + /// Contains a scrollable TextArea. + /// </summary> + [Localizability(LocalizationCategory.Text), ContentProperty("Text")] + public class TextEditor : Control, ITextEditorComponent, IServiceProvider, IWeakEventListener + { + #region Constructors + static TextEditor() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TextEditor), + new FrameworkPropertyMetadata(typeof(TextEditor))); + FocusableProperty.OverrideMetadata(typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.True)); + } + + /// <summary> + /// Creates a new TextEditor instance. + /// </summary> + public TextEditor() : this(new TextArea()) + { + } + + /// <summary> + /// Creates a new TextEditor instance. + /// </summary> + protected TextEditor(TextArea textArea) + { + if (textArea == null) + throw new ArgumentNullException("textArea"); + this.textArea = textArea; + + textArea.TextView.Services.AddService(typeof(TextEditor), this); + + SetCurrentValue(OptionsProperty, textArea.Options); + SetCurrentValue(DocumentProperty, new TextDocument()); + } + + #endregion + + /// <inheritdoc/> + protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer() + { + return new TextEditorAutomationPeer(this); + } + + /// Forward focus to TextArea. + /// <inheritdoc/> + protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) + { + base.OnGotKeyboardFocus(e); + if (e.NewFocus == this) + { + Keyboard.Focus(this.TextArea); + e.Handled = true; + } + } + + #region Document property + /// <summary> + /// Document property. + /// </summary> + public static readonly DependencyProperty DocumentProperty + = TextView.DocumentProperty.AddOwner( + typeof(TextEditor), new FrameworkPropertyMetadata(OnDocumentChanged)); + + /// <summary> + /// Gets/Sets the document displayed by the text editor. + /// This is a dependency property. + /// </summary> + public TextDocument Document + { + get { return (TextDocument)GetValue(DocumentProperty); } + set { SetValue(DocumentProperty, value); } + } + + /// <summary> + /// Occurs when the document property has changed. + /// </summary> + public event EventHandler DocumentChanged; + + /// <summary> + /// Raises the <see cref="DocumentChanged"/> event. + /// </summary> + protected virtual void OnDocumentChanged(EventArgs e) + { + if (DocumentChanged != null) + { + DocumentChanged(this, e); + } + } + + static void OnDocumentChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) + { + ((TextEditor)dp).OnDocumentChanged((TextDocument)e.OldValue, (TextDocument)e.NewValue); + } + + void OnDocumentChanged(TextDocument oldValue, TextDocument newValue) + { + if (oldValue != null) + { + TextDocumentWeakEventManager.TextChanged.RemoveListener(oldValue, this); + PropertyChangedEventManager.RemoveListener(oldValue.UndoStack, this, "IsOriginalFile"); + } + textArea.Document = newValue; + if (newValue != null) + { + TextDocumentWeakEventManager.TextChanged.AddListener(newValue, this); + PropertyChangedEventManager.AddListener(newValue.UndoStack, this, "IsOriginalFile"); + } + OnDocumentChanged(EventArgs.Empty); + OnTextChanged(EventArgs.Empty); + } + #endregion + + #region Options property + /// <summary> + /// Options property. + /// </summary> + public static readonly DependencyProperty OptionsProperty + = TextView.OptionsProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(OnOptionsChanged)); + + /// <summary> + /// Gets/Sets the options currently used by the text editor. + /// </summary> + public TextEditorOptions Options + { + get { return (TextEditorOptions)GetValue(OptionsProperty); } + set { SetValue(OptionsProperty, value); } + } + + /// <summary> + /// Occurs when a text editor option has changed. + /// </summary> + public event PropertyChangedEventHandler OptionChanged; + + /// <summary> + /// Raises the <see cref="OptionChanged"/> event. + /// </summary> + protected virtual void OnOptionChanged(PropertyChangedEventArgs e) + { + if (OptionChanged != null) + { + OptionChanged(this, e); + } + } + + static void OnOptionsChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e) + { + ((TextEditor)dp).OnOptionsChanged((TextEditorOptions)e.OldValue, (TextEditorOptions)e.NewValue); + } + + void OnOptionsChanged(TextEditorOptions oldValue, TextEditorOptions newValue) + { + if (oldValue != null) + { + PropertyChangedWeakEventManager.RemoveListener(oldValue, this); + } + textArea.Options = newValue; + if (newValue != null) + { + PropertyChangedWeakEventManager.AddListener(newValue, this); + } + OnOptionChanged(new PropertyChangedEventArgs(null)); + } + + /// <inheritdoc cref="IWeakEventListener.ReceiveWeakEvent"/> + protected virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + if (managerType == typeof(PropertyChangedWeakEventManager)) + { + OnOptionChanged((PropertyChangedEventArgs)e); + return true; + } + else if (managerType == typeof(TextDocumentWeakEventManager.TextChanged)) + { + OnTextChanged(e); + return true; + } + else if (managerType == typeof(PropertyChangedEventManager)) + { + return HandleIsOriginalChanged((PropertyChangedEventArgs)e); + } + return false; + } + + bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + return ReceiveWeakEvent(managerType, sender, e); + } + #endregion + + #region Text property + /// <summary> + /// Gets/Sets the text of the current document. + /// </summary> + [Localizability(LocalizationCategory.Text), DefaultValue("")] + public string Text + { + get + { + TextDocument document = this.Document; + return document != null ? document.Text : string.Empty; + } + set + { + TextDocument document = GetDocument(); + document.Text = value ?? string.Empty; + // after replacing the full text, the caret is positioned at the end of the document + // - reset it to the beginning. + this.CaretOffset = 0; + document.UndoStack.ClearAll(); + } + } + + TextDocument GetDocument() + { + TextDocument document = this.Document; + if (document == null) + throw ThrowUtil.NoDocumentAssigned(); + return document; + } + + /// <summary> + /// Occurs when the Text property changes. + /// </summary> + public event EventHandler TextChanged; + + /// <summary> + /// Raises the <see cref="TextChanged"/> event. + /// </summary> + protected virtual void OnTextChanged(EventArgs e) + { + if (TextChanged != null) + { + TextChanged(this, e); + } + } + #endregion + + #region TextArea / ScrollViewer properties + readonly TextArea textArea; + ScrollViewer scrollViewer; + + /// <summary> + /// Is called after the template was applied. + /// </summary> + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + scrollViewer = (ScrollViewer)Template.FindName("PART_ScrollViewer", this); + } + + /// <summary> + /// Gets the text area. + /// </summary> + public TextArea TextArea + { + get + { + return textArea; + } + } + + /// <summary> + /// Gets the scroll viewer used by the text editor. + /// This property can return null if the template has not been applied / does not contain a scroll viewer. + /// </summary> + internal ScrollViewer ScrollViewer + { + get { return scrollViewer; } + } + + bool CanExecute(RoutedUICommand command) + { + TextArea textArea = this.TextArea; + if (textArea == null) + return false; + else + return command.CanExecute(null, textArea); + } + + void Execute(RoutedUICommand command) + { + TextArea textArea = this.TextArea; + if (textArea != null) + command.Execute(null, textArea); + } + #endregion + + #region Syntax highlighting + /// <summary> + /// The <see cref="SyntaxHighlighting"/> property. + /// </summary> + public static readonly DependencyProperty SyntaxHighlightingProperty = + DependencyProperty.Register("SyntaxHighlighting", typeof(IHighlightingDefinition), typeof(TextEditor), + new FrameworkPropertyMetadata(OnSyntaxHighlightingChanged)); + + + /// <summary> + /// Gets/sets the syntax highlighting definition used to colorize the text. + /// </summary> + public IHighlightingDefinition SyntaxHighlighting + { + get { return (IHighlightingDefinition)GetValue(SyntaxHighlightingProperty); } + set { SetValue(SyntaxHighlightingProperty, value); } + } + + IVisualLineTransformer colorizer; + + static void OnSyntaxHighlightingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((TextEditor)d).OnSyntaxHighlightingChanged(e.NewValue as IHighlightingDefinition); + } + + void OnSyntaxHighlightingChanged(IHighlightingDefinition newValue) + { + if (colorizer != null) + { + this.TextArea.TextView.LineTransformers.Remove(colorizer); + colorizer = null; + } + if (newValue != null) + { + colorizer = CreateColorizer(newValue); + this.TextArea.TextView.LineTransformers.Insert(0, colorizer); + } + } + + /// <summary> + /// Creates the highlighting colorizer for the specified highlighting definition. + /// Allows derived classes to provide custom colorizer implementations for special highlighting definitions. + /// </summary> + /// <returns></returns> + protected virtual IVisualLineTransformer CreateColorizer(IHighlightingDefinition highlightingDefinition) + { + if (highlightingDefinition == null) + throw new ArgumentNullException("highlightingDefinition"); + return new HighlightingColorizer(highlightingDefinition.MainRuleSet); + } + #endregion + + #region WordWrap + /// <summary> + /// Word wrap dependency property. + /// </summary> + public static readonly DependencyProperty WordWrapProperty = + DependencyProperty.Register("WordWrap", typeof(bool), typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.False)); + + /// <summary> + /// Specifies whether the text editor uses word wrapping. + /// </summary> + /// <remarks> + /// Setting WordWrap=true has the same effect as setting HorizontalScrollBarVisibility=Disabled and will override the + /// HorizontalScrollBarVisibility setting. + /// </remarks> + public bool WordWrap + { + get { return (bool)GetValue(WordWrapProperty); } + set { SetValue(WordWrapProperty, Boxes.Box(value)); } + } + #endregion + + #region IsReadOnly + /// <summary> + /// IsReadOnly dependency property. + /// </summary> + public static readonly DependencyProperty IsReadOnlyProperty = + DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.False, OnIsReadOnlyChanged)); + + /// <summary> + /// Specifies whether the user can change the text editor content. + /// Setting this property will replace the + /// <see cref="Editing.TextArea.ReadOnlySectionProvider">TextArea.ReadOnlySectionProvider</see>. + /// </summary> + public bool IsReadOnly + { + get { return (bool)GetValue(IsReadOnlyProperty); } + set { SetValue(IsReadOnlyProperty, Boxes.Box(value)); } + } + + static void OnIsReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextEditor editor = d as TextEditor; + if (editor != null) + { + if ((bool)e.NewValue) + editor.TextArea.ReadOnlySectionProvider = ReadOnlyDocument.Instance; + else + editor.TextArea.ReadOnlySectionProvider = NoReadOnlySections.Instance; + + TextEditorAutomationPeer peer = TextEditorAutomationPeer.FromElement(editor) as TextEditorAutomationPeer; + if (peer != null) + { + peer.RaiseIsReadOnlyChanged((bool)e.OldValue, (bool)e.NewValue); + } + } + } + #endregion + + #region IsModified + /// <summary> + /// Dependency property for <see cref="IsModified"/> + /// </summary> + public static readonly DependencyProperty IsModifiedProperty = + DependencyProperty.Register("IsModified", typeof(bool), typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.False, OnIsModifiedChanged)); + + /// <summary> + /// Gets/Sets the 'modified' flag. + /// </summary> + public bool IsModified + { + get { return (bool)GetValue(IsModifiedProperty); } + set { SetValue(IsModifiedProperty, Boxes.Box(value)); } + } + + static void OnIsModifiedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextEditor editor = d as TextEditor; + if (editor != null) + { + TextDocument document = editor.Document; + if (document != null) + { + UndoStack undoStack = document.UndoStack; + if ((bool)e.NewValue) + { + if (undoStack.IsOriginalFile) + undoStack.DiscardOriginalFileMarker(); + } + else + { + undoStack.MarkAsOriginalFile(); + } + } + } + } + + bool HandleIsOriginalChanged(PropertyChangedEventArgs e) + { + if (e.PropertyName == "IsOriginalFile") + { + TextDocument document = this.Document; + if (document != null) + { + SetCurrentValue(IsModifiedProperty, Boxes.Box(!document.UndoStack.IsOriginalFile)); + } + return true; + } + else + { + return false; + } + } + #endregion + + #region ShowLineNumbers + /// <summary> + /// ShowLineNumbers dependency property. + /// </summary> + public static readonly DependencyProperty ShowLineNumbersProperty = + DependencyProperty.Register("ShowLineNumbers", typeof(bool), typeof(TextEditor), + new FrameworkPropertyMetadata(Boxes.False, OnShowLineNumbersChanged)); + + /// <summary> + /// Specifies whether line numbers are shown on the left to the text view. + /// </summary> + public bool ShowLineNumbers + { + get { return (bool)GetValue(ShowLineNumbersProperty); } + set { SetValue(ShowLineNumbersProperty, Boxes.Box(value)); } + } + + static void OnShowLineNumbersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextEditor editor = (TextEditor)d; + var leftMargins = editor.TextArea.LeftMargins; + if ((bool)e.NewValue) + { + LineNumberMargin lineNumbers = new LineNumberMargin(); + Line line = (Line)DottedLineMargin.Create(); + leftMargins.Insert(0, lineNumbers); + leftMargins.Insert(1, line); + var lineNumbersForeground = new Binding("LineNumbersForeground") { Source = editor }; + line.SetBinding(Line.StrokeProperty, lineNumbersForeground); + lineNumbers.SetBinding(Control.ForegroundProperty, lineNumbersForeground); + } + else + { + for (int i = 0; i < leftMargins.Count; i++) + { + if (leftMargins[i] is LineNumberMargin) + { + leftMargins.RemoveAt(i); + if (i < leftMargins.Count && DottedLineMargin.IsDottedLineMargin(leftMargins[i])) + { + leftMargins.RemoveAt(i); + } + break; + } + } + } + } + #endregion + + #region LineNumbersForeground + /// <summary> + /// LineNumbersForeground dependency property. + /// </summary> + public static readonly DependencyProperty LineNumbersForegroundProperty = + DependencyProperty.Register("LineNumbersForeground", typeof(Brush), typeof(TextEditor), + new FrameworkPropertyMetadata(Brushes.Gray, OnLineNumbersForegroundChanged)); + + /// <summary> + /// Gets/sets the Brush used for displaying the foreground color of line numbers. + /// </summary> + public Brush LineNumbersForeground + { + get { return (Brush)GetValue(LineNumbersForegroundProperty); } + set { SetValue(LineNumbersForegroundProperty, value); } + } + + static void OnLineNumbersForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TextEditor editor = (TextEditor)d; + var lineNumberMargin = editor.TextArea.LeftMargins.FirstOrDefault(margin => margin is LineNumberMargin) as LineNumberMargin; ; + + if (lineNumberMargin != null) + { + lineNumberMargin.SetValue(Control.ForegroundProperty, e.NewValue); + } + } + #endregion + + #region TextBoxBase-like methods + /// <summary> + /// Appends text to the end of the document. + /// </summary> + public void AppendText(string textData) + { + var document = GetDocument(); + document.Insert(document.TextLength, textData); + } + + /// <summary> + /// Begins a group of document changes. + /// </summary> + public void BeginChange() + { + GetDocument().BeginUpdate(); + } + + /// <summary> + /// Copies the current selection to the clipboard. + /// </summary> + public void Copy() + { + Execute(ApplicationCommands.Copy); + } + + /// <summary> + /// Removes the current selection and copies it to the clipboard. + /// </summary> + public void Cut() + { + Execute(ApplicationCommands.Cut); + } + + /// <summary> + /// Begins a group of document changes and returns an object that ends the group of document + /// changes when it is disposed. + /// </summary> + public IDisposable DeclareChangeBlock() + { + return GetDocument().RunUpdate(); + } + + /// <summary> + /// Ends the current group of document changes. + /// </summary> + public void EndChange() + { + GetDocument().EndUpdate(); + } + + /// <summary> + /// Scrolls one line down. + /// </summary> + public void LineDown() + { + if (scrollViewer != null) + scrollViewer.LineDown(); + } + + /// <summary> + /// Scrolls to the left. + /// </summary> + public void LineLeft() + { + if (scrollViewer != null) + scrollViewer.LineLeft(); + } + + /// <summary> + /// Scrolls to the right. + /// </summary> + public void LineRight() + { + if (scrollViewer != null) + scrollViewer.LineRight(); + } + + /// <summary> + /// Scrolls one line up. + /// </summary> + public void LineUp() + { + if (scrollViewer != null) + scrollViewer.LineUp(); + } + + /// <summary> + /// Scrolls one page down. + /// </summary> + public void PageDown() + { + if (scrollViewer != null) + scrollViewer.PageDown(); + } + + /// <summary> + /// Scrolls one page up. + /// </summary> + public void PageUp() + { + if (scrollViewer != null) + scrollViewer.PageUp(); + } + + /// <summary> + /// Scrolls one page left. + /// </summary> + public void PageLeft() + { + if (scrollViewer != null) + scrollViewer.PageLeft(); + } + + /// <summary> + /// Scrolls one page right. + /// </summary> + public void PageRight() + { + if (scrollViewer != null) + scrollViewer.PageRight(); + } + + /// <summary> + /// Pastes the clipboard content. + /// </summary> + public void Paste() + { + Execute(ApplicationCommands.Paste); + } + + /// <summary> + /// Redoes the most recent undone command. + /// </summary> + /// <returns>True is the redo operation was successful, false is the redo stack is empty.</returns> + public bool Redo() + { + if (CanExecute(ApplicationCommands.Redo)) + { + Execute(ApplicationCommands.Redo); + return true; + } + return false; + } + + /// <summary> + /// Scrolls to the end of the document. + /// </summary> + public void ScrollToEnd() + { + ApplyTemplate(); // ensure scrollViewer is created + if (scrollViewer != null) + scrollViewer.ScrollToEnd(); + } + + /// <summary> + /// Scrolls to the start of the document. + /// </summary> + public void ScrollToHome() + { + ApplyTemplate(); // ensure scrollViewer is created + if (scrollViewer != null) + scrollViewer.ScrollToHome(); + } + + /// <summary> + /// Scrolls to the specified position in the document. + /// </summary> + public void ScrollToHorizontalOffset(double offset) + { + ApplyTemplate(); // ensure scrollViewer is created + if (scrollViewer != null) + scrollViewer.ScrollToHorizontalOffset(offset); + } + + /// <summary> + /// Scrolls to the specified position in the document. + /// </summary> + public void ScrollToVerticalOffset(double offset) + { + ApplyTemplate(); // ensure scrollViewer is created + if (scrollViewer != null) + scrollViewer.ScrollToVerticalOffset(offset); + } + + /// <summary> + /// Selects the entire text. + /// </summary> + public void SelectAll() + { + Execute(ApplicationCommands.SelectAll); + } + + /// <summary> + /// Undoes the most recent command. + /// </summary> + /// <returns>True is the undo operation was successful, false is the undo stack is empty.</returns> + public bool Undo() + { + if (CanExecute(ApplicationCommands.Undo)) + { + Execute(ApplicationCommands.Undo); + return true; + } + return false; + } + + /// <summary> + /// Gets if the most recent undone command can be redone. + /// </summary> + public bool CanRedo + { + get { return CanExecute(ApplicationCommands.Redo); } + } + + /// <summary> + /// Gets if the most recent command can be undone. + /// </summary> + public bool CanUndo + { + get { return CanExecute(ApplicationCommands.Undo); } + } + + /// <summary> + /// Gets the vertical size of the document. + /// </summary> + public double ExtentHeight + { + get + { + return scrollViewer != null ? scrollViewer.ExtentHeight : 0; + } + } + + /// <summary> + /// Gets the horizontal size of the current document region. + /// </summary> + public double ExtentWidth + { + get + { + return scrollViewer != null ? scrollViewer.ExtentWidth : 0; + } + } + + /// <summary> + /// Gets the horizontal size of the viewport. + /// </summary> + public double ViewportHeight + { + get + { + return scrollViewer != null ? scrollViewer.ViewportHeight : 0; + } + } + + /// <summary> + /// Gets the horizontal size of the viewport. + /// </summary> + public double ViewportWidth + { + get + { + return scrollViewer != null ? scrollViewer.ViewportWidth : 0; + } + } + + /// <summary> + /// Gets the vertical scroll position. + /// </summary> + public double VerticalOffset + { + get + { + return scrollViewer != null ? scrollViewer.VerticalOffset : 0; + } + } + + /// <summary> + /// Gets the horizontal scroll position. + /// </summary> + public double HorizontalOffset + { + get + { + return scrollViewer != null ? scrollViewer.HorizontalOffset : 0; + } + } + #endregion + + #region TextBox methods + /// <summary> + /// Gets/Sets the selected text. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string SelectedText + { + get + { + TextArea textArea = this.TextArea; + // We'll get the text from the whole surrounding segment. + // This is done to ensure that SelectedText.Length == SelectionLength. + if (textArea != null && textArea.Document != null && !textArea.Selection.IsEmpty) + return textArea.Document.GetText(textArea.Selection.SurroundingSegment); + else + return string.Empty; + } + set + { + if (value == null) + throw new ArgumentNullException("value"); + TextArea textArea = this.TextArea; + if (textArea != null && textArea.Document != null) + { + int offset = this.SelectionStart; + int length = this.SelectionLength; + textArea.Document.Replace(offset, length, value); + // keep inserted text selected + textArea.Selection = SimpleSelection.Create(textArea, offset, offset + value.Length); + } + } + } + + /// <summary> + /// Gets/sets the caret position. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int CaretOffset + { + get + { + TextArea textArea = this.TextArea; + if (textArea != null) + return textArea.Caret.Offset; + else + return 0; + } + set + { + TextArea textArea = this.TextArea; + if (textArea != null) + textArea.Caret.Offset = value; + } + } + + /// <summary> + /// Gets/sets the start position of the selection. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int SelectionStart + { + get + { + TextArea textArea = this.TextArea; + if (textArea != null) + { + if (textArea.Selection.IsEmpty) + return textArea.Caret.Offset; + else + return textArea.Selection.SurroundingSegment.Offset; + } + else + { + return 0; + } + } + set + { + Select(value, SelectionLength); + } + } + + /// <summary> + /// Gets/sets the length of the selection. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int SelectionLength + { + get + { + TextArea textArea = this.TextArea; + if (textArea != null && !textArea.Selection.IsEmpty) + return textArea.Selection.SurroundingSegment.Length; + else + return 0; + } + set + { + Select(SelectionStart, value); + } + } + + /// <summary> + /// Selects the specified text section. + /// </summary> + public void Select(int start, int length) + { + int documentLength = Document != null ? Document.TextLength : 0; + + if (start < 0 || start > documentLength) + { + Debug.WriteLine(new ArgumentOutOfRangeException("start", start, "Value must be between 0 and " + documentLength)); + return; + } + + if (length < 0 || start + length > documentLength) + { + Debug.WriteLine(new ArgumentOutOfRangeException("length", length, "Value must be between 0 and " + (documentLength - length))); + return; + } + + textArea.Selection = SimpleSelection.Create(textArea, start, start + length); + textArea.Caret.Offset = start + length; + } + + /// <summary> + /// Gets the number of lines in the document. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int LineCount + { + get + { + TextDocument document = this.Document; + if (document != null) + return document.LineCount; + else + return 1; + } + } + + /// <summary> + /// Clears the text. + /// </summary> + public void Clear() + { + this.Text = string.Empty; + } + #endregion + + #region Loading from stream + /// <summary> + /// Loads the text from the stream, auto-detecting the encoding. + /// </summary> + /// <remarks> + /// This method sets <see cref="IsModified"/> to false. + /// </remarks> + public void Load(Stream stream) + { + using (StreamReader reader = FileReader.OpenStream(stream, this.Encoding ?? Encoding.UTF8)) + { + this.Text = reader.ReadToEnd(); + this.Encoding = reader.CurrentEncoding; // assign encoding after ReadToEnd() so that the StreamReader can autodetect the encoding + } + this.IsModified = false; + } + + /// <summary> + /// Loads the text from the stream, auto-detecting the encoding. + /// </summary> + public void Load(string fileName) + { + if (fileName == null) + throw new ArgumentNullException("fileName"); + using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + Load(fs); + } + } + + /// <summary> + /// Gets/sets the encoding used when the file is saved. + /// </summary> + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Encoding Encoding { get; set; } + + /// <summary> + /// Saves the text to the stream. + /// </summary> + /// <remarks> + /// This method sets <see cref="IsModified"/> to false. + /// </remarks> + public void Save(Stream stream) + { + if (stream == null) + throw new ArgumentNullException("stream"); + StreamWriter writer = new StreamWriter(stream, this.Encoding ?? Encoding.UTF8); + writer.Write(this.Text); + writer.Flush(); + // do not close the stream + this.IsModified = false; + } + + /// <summary> + /// Saves the text to the file. + /// </summary> + public void Save(string fileName) + { + if (fileName == null) + throw new ArgumentNullException("fileName"); + using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) + { + Save(fs); + } + } + #endregion + + #region MouseHover events + /// <summary> + /// The PreviewMouseHover event. + /// </summary> + public static readonly RoutedEvent PreviewMouseHoverEvent = + TextView.PreviewMouseHoverEvent.AddOwner(typeof(TextEditor)); + + /// <summary> + /// The MouseHover event. + /// </summary> + public static readonly RoutedEvent MouseHoverEvent = + TextView.MouseHoverEvent.AddOwner(typeof(TextEditor)); + + + /// <summary> + /// The PreviewMouseHoverStopped event. + /// </summary> + public static readonly RoutedEvent PreviewMouseHoverStoppedEvent = + TextView.PreviewMouseHoverStoppedEvent.AddOwner(typeof(TextEditor)); + + /// <summary> + /// The MouseHoverStopped event. + /// </summary> + public static readonly RoutedEvent MouseHoverStoppedEvent = + TextView.MouseHoverStoppedEvent.AddOwner(typeof(TextEditor)); + + + /// <summary> + /// Occurs when the mouse has hovered over a fixed location for some time. + /// </summary> + public event MouseEventHandler PreviewMouseHover + { + add { AddHandler(PreviewMouseHoverEvent, value); } + remove { RemoveHandler(PreviewMouseHoverEvent, value); } + } + + /// <summary> + /// Occurs when the mouse has hovered over a fixed location for some time. + /// </summary> + public event MouseEventHandler MouseHover + { + add { AddHandler(MouseHoverEvent, value); } + remove { RemoveHandler(MouseHoverEvent, value); } + } + + /// <summary> + /// Occurs when the mouse had previously hovered but now started moving again. + /// </summary> + public event MouseEventHandler PreviewMouseHoverStopped + { + add { AddHandler(PreviewMouseHoverStoppedEvent, value); } + remove { RemoveHandler(PreviewMouseHoverStoppedEvent, value); } + } + + /// <summary> + /// Occurs when the mouse had previously hovered but now started moving again. + /// </summary> + public event MouseEventHandler MouseHoverStopped + { + add { AddHandler(MouseHoverStoppedEvent, value); } + remove { RemoveHandler(MouseHoverStoppedEvent, value); } + } + #endregion + + #region ScrollBarVisibility + /// <summary> + /// Dependency property for <see cref="HorizontalScrollBarVisibility"/> + /// </summary> + public static readonly DependencyProperty HorizontalScrollBarVisibilityProperty = ScrollViewer.HorizontalScrollBarVisibilityProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(ScrollBarVisibility.Visible)); + + /// <summary> + /// Gets/Sets the horizontal scroll bar visibility. + /// </summary> + public ScrollBarVisibility HorizontalScrollBarVisibility + { + get { return (ScrollBarVisibility)GetValue(HorizontalScrollBarVisibilityProperty); } + set { SetValue(HorizontalScrollBarVisibilityProperty, value); } + } + + /// <summary> + /// Dependency property for <see cref="VerticalScrollBarVisibility"/> + /// </summary> + public static readonly DependencyProperty VerticalScrollBarVisibilityProperty = ScrollViewer.VerticalScrollBarVisibilityProperty.AddOwner(typeof(TextEditor), new FrameworkPropertyMetadata(ScrollBarVisibility.Visible)); + + /// <summary> + /// Gets/Sets the vertical scroll bar visibility. + /// </summary> + public ScrollBarVisibility VerticalScrollBarVisibility + { + get { return (ScrollBarVisibility)GetValue(VerticalScrollBarVisibilityProperty); } + set { SetValue(VerticalScrollBarVisibilityProperty, value); } + } + #endregion + + object IServiceProvider.GetService(Type serviceType) + { + return textArea.GetService(serviceType); + } + + /// <summary> + /// Gets the text view position from a point inside the editor. + /// </summary> + /// <param name="point">The position, relative to top left + /// corner of TextEditor control</param> + /// <returns>The text view position, or null if the point is outside the document.</returns> + public TextViewPosition? GetPositionFromPoint(Point point) + { + if (this.Document == null) + return null; + TextView textView = this.TextArea.TextView; + return textView.GetPosition(TranslatePoint(point, textView) + textView.ScrollOffset); + } + + /// <summary> + /// Scrolls to the specified line. + /// This method requires that the TextEditor was already assigned a size (WPF layout must have run prior). + /// </summary> + public void ScrollToLine(int line) + { + ScrollTo(line, -1); + } + + /// <summary> + /// Scrolls to the specified line/column. + /// This method requires that the TextEditor was already assigned a size (WPF layout must have run prior). + /// </summary> + public void ScrollTo(int line, int column) + { + const double MinimumScrollPercentage = 0.3; + + TextView textView = textArea.TextView; + TextDocument document = textView.Document; + if (scrollViewer != null && document != null) + { + if (line < 1) + line = 1; + if (line > document.LineCount) + line = document.LineCount; + + IScrollInfo scrollInfo = textView; + if (!scrollInfo.CanHorizontallyScroll) + { + // Word wrap is enabled. Ensure that we have up-to-date info about line height so that we scroll + // to the correct position. + // This avoids that the user has to repeat the ScrollTo() call several times when there are very long lines. + VisualLine vl = textView.GetOrConstructVisualLine(document.GetLineByNumber(line)); + double remainingHeight = scrollViewer.ViewportHeight / 2; + while (remainingHeight > 0) + { + DocumentLine prevLine = vl.FirstDocumentLine.PreviousLine; + if (prevLine == null) + break; + vl = textView.GetOrConstructVisualLine(prevLine); + remainingHeight -= vl.Height; + } + } + + Point p = textArea.TextView.GetVisualPosition(new TextViewPosition(line, Math.Max(1, column)), VisualYPosition.LineMiddle); + double verticalPos = p.Y - scrollViewer.ViewportHeight / 2; + if (Math.Abs(verticalPos - scrollViewer.VerticalOffset) > MinimumScrollPercentage * scrollViewer.ViewportHeight) + { + scrollViewer.ScrollToVerticalOffset(Math.Max(0, verticalPos)); + } + if (column > 0) + { + if (p.X > scrollViewer.ViewportWidth - Caret.MinimumDistanceToViewBorder * 2) + { + double horizontalPos = Math.Max(0, p.X - scrollViewer.ViewportWidth / 2); + if (Math.Abs(horizontalPos - scrollViewer.HorizontalOffset) > MinimumScrollPercentage * scrollViewer.ViewportWidth) + { + scrollViewer.ScrollToHorizontalOffset(horizontalPos); + } + } + else + { + scrollViewer.ScrollToHorizontalOffset(0); + } + } + } + } + } }
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs index e9cb8fc4c..2e7086ce0 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs @@ -138,9 +138,32 @@ namespace Tango.Scripting.Parsing varSymbol.Type = type; varSymbol.Class = ReplaceFakeScript(symbol.ContainingType?.Name); varSymbol.Kind = symbol.Kind; + varSymbol.RealSymbol = symbol; varSymbol.Accessibility = symbol.DeclaredAccessibility; varSymbol.ContainingNamespace = ReplaceFakeScript(symbol.ContainingNamespace?.Name); varSymbol.Summary = GetSymbolDocumentation(symbol); + + try + { + if (symbol.Kind == SymbolKind.Local && symbol.DeclaringSyntaxReferences.Count() > 0) + { + var node = symbol.DeclaringSyntaxReferences.First().GetSyntax() as VariableDeclaratorSyntax; + + if (node != null) + { + varSymbol.IsUnassigned = node.Initializer == null; + } + } + } + catch { } + + try + { + varSymbol.Offset = symbol.Locations[0].SourceSpan.Start; + varSymbol.Length = symbol.Locations[0].SourceSpan.Length; + } + catch { } + vars.Add(varSymbol); if (type == "?") diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs index d6fdaeebf..4b34837af 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs @@ -17,6 +17,10 @@ namespace Tango.Scripting.Parsing public String ContainingNamespace { get; set; } public List<KeyValuePair<String,String>> Parameters { get; set; } public String Summary { get; set; } + public int Offset { get; set; } + public int Length { get; set; } + public bool IsUnassigned { get; set; } + public ISymbol RealSymbol { get; set; } public ScriptSymbol() { |
