diff options
| author | Mirta <mirta@twine-s.com> | 2020-12-30 16:39:52 +0200 |
|---|---|---|
| committer | Mirta <mirta@twine-s.com> | 2020-12-30 16:39:52 +0200 |
| commit | 00a491d93733d4625ad329b2ba8237f445364b3f (patch) | |
| tree | 4b24c6fa78d7648f4bb7cefafa464bb0b063fec4 /Software/Visual_Studio/Scripting/Tango.Scripting.Editors | |
| parent | 124ad4150f80c6846fdee41dbbda9848c105f6e5 (diff) | |
| download | Tango-00a491d9.tar.gz Tango-00a491d9.zip | |
merge
Diffstat (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting.Editors')
33 files changed, 2469 insertions, 5497 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs deleted file mode 100644 index 1728bb565..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/BreakPointSymbolPressedEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -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/CachedAssembly.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedAssembly.cs deleted file mode 100644 index b0178e63e..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedAssembly.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.Scripting.Editors.Intellisense; - -namespace Tango.Scripting.Editors -{ - public class CachedAssembly - { - public String Name { get; set; } - public List<KnownType> KnownTypes { get; set; } - - public CachedAssembly() - { - KnownTypes = new List<KnownType>(); - } - } -} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedUsing.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedUsing.cs deleted file mode 100644 index 4a663bee9..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/CachedUsing.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.Scripting.Editors.Intellisense; - -namespace Tango.Scripting.Editors -{ - public class CachedUsing - { - public String Namespace { get; set; } - public List<KnownType> KnownTypes { get; set; } - - public CachedUsing() - { - KnownTypes = new List<KnownType>(); - } - } -} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextDocument.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextDocument.cs index a95d07fcf..84fc86f44 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextDocument.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/TextDocument.cs @@ -14,884 +14,823 @@ using Tango.Scripting.Editors.Utils; namespace Tango.Scripting.Editors.Document { - /// <summary> - /// This class is the main class of the text model. Basically, it is a <see cref="System.Text.StringBuilder"/> with events. - /// </summary> - /// <remarks> - /// <b>Thread safety:</b> - /// <inheritdoc cref="VerifyAccess"/> - /// <para>However, there is a single method that is thread-safe: <see cref="CreateSnapshot()"/> (and its overloads).</para> - /// </remarks> - public sealed class TextDocument : ITextSource, INotifyPropertyChanged - { - #region Thread ownership - readonly object lockObject = new object(); - Thread owner = Thread.CurrentThread; - - /// <summary> - /// Verifies that the current thread is the documents owner thread. - /// Throws an <see cref="InvalidOperationException"/> if the wrong thread accesses the TextDocument. - /// </summary> - /// <remarks> - /// <para>The TextDocument class is not thread-safe. A document instance expects to have a single owner thread - /// and will throw an <see cref="InvalidOperationException"/> when accessed from another thread. - /// It is possible to change the owner thread using the <see cref="SetOwnerThread"/> method.</para> - /// </remarks> - public void VerifyAccess() - { - if (Thread.CurrentThread != owner) - throw new InvalidOperationException("TextDocument can be accessed only from the thread that owns it."); - } - - /// <summary> - /// Transfers ownership of the document to another thread. This method can be used to load - /// a file into a TextDocument on a background thread and then transfer ownership to the UI thread - /// for displaying the document. - /// </summary> - /// <remarks> - /// <inheritdoc cref="VerifyAccess"/> - /// <para> - /// The owner can be set to null, which means that no thread can access the document. But, if the document - /// has no owner thread, any thread may take ownership by calling <see cref="SetOwnerThread"/>. - /// </para> - /// </remarks> - public void SetOwnerThread(Thread newOwner) - { - // We need to lock here to ensure that in the null owner case, - // only one thread succeeds in taking ownership. - lock (lockObject) - { - if (owner != null) - { - VerifyAccess(); - } - owner = newOwner; - } - } - #endregion - - #region Fields + Constructor - readonly Rope<char> rope; - readonly DocumentLineTree lineTree; - readonly LineManager lineManager; - readonly TextAnchorTree anchorTree; - ChangeTrackingCheckpoint currentCheckpoint; - - /// <summary> - /// Create an empty text document. - /// </summary> - public TextDocument() - : this(string.Empty) - { - } - - /// <summary> - /// Create a new text document with the specified initial text. - /// </summary> - public TextDocument(IEnumerable<char> initialText) - { - if (initialText == null) - throw new ArgumentNullException("initialText"); - rope = new Rope<char>(initialText); - lineTree = new DocumentLineTree(this); - lineManager = new LineManager(lineTree, this); - lineTrackers.CollectionChanged += delegate - { - lineManager.UpdateListOfLineTrackers(); - }; - - anchorTree = new TextAnchorTree(this); - undoStack = new UndoStack(); - FireChangeEvents(); - } - - /// <summary> - /// Create a new text document with the specified initial text. - /// </summary> - public TextDocument(ITextSource initialText) - : this(GetTextFromTextSource(initialText)) - { - } - - // gets the text from a text source, directly retrieving the underlying rope where possible - static IEnumerable<char> GetTextFromTextSource(ITextSource textSource) - { - if (textSource == null) - throw new ArgumentNullException("textSource"); - - RopeTextSource rts = textSource as RopeTextSource; - if (rts != null) - return rts.GetRope(); - - TextDocument doc = textSource as TextDocument; - if (doc != null) - return doc.rope; - - return textSource.Text; - } - #endregion - - #region Text - void ThrowIfRangeInvalid(int offset, int length) - { - if (offset < 0 || offset > rope.Length) - { - throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); - } - if (length < 0 || offset + length > rope.Length) - { - throw new ArgumentOutOfRangeException("length", length, "0 <= length, offset(" + offset + ")+length <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); - } - } - - /// <inheritdoc/> - public string GetText(int offset, int length) - { - VerifyAccess(); - return rope.ToString(Math.Max(offset, 0), length); - } - - /// <summary> - /// Retrieves the text for a portion of the document. - /// </summary> - public string GetText(ISegment segment) - { - if (segment == null) - throw new ArgumentNullException("segment"); - return GetText(segment.Offset, segment.Length); - } - - int ITextSource.IndexOfAny(char[] anyOf, int startIndex, int count) - { - DebugVerifyAccess(); // frequently called (NewLineFinder), so must be fast in release builds - return rope.IndexOfAny(anyOf, startIndex, count); - } - - /// <inheritdoc/> - public char GetCharAt(int offset) - { - DebugVerifyAccess(); // frequently called, so must be fast in release builds - return rope[offset]; - } - - WeakReference cachedText; - - /// <summary> - /// Gets/Sets the text of the whole document. - /// </summary> - public string Text - { - get - { - VerifyAccess(); - string completeText = cachedText != null ? (cachedText.Target as string) : null; - if (completeText == null) - { - completeText = rope.ToString(); - cachedText = new WeakReference(completeText); - } - return completeText; - } - set - { - VerifyAccess(); - if (value == null) - throw new ArgumentNullException("value"); - Replace(0, rope.Length, value); - } - } - - /// <inheritdoc/> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event EventHandler TextChanged; - - /// <inheritdoc/> - public int TextLength - { - get - { - VerifyAccess(); - return rope.Length; - } - } - - /// <summary> - /// Is raised when the TextLength property changes. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - [Obsolete("This event will be removed in a future version; use the PropertyChanged event instead")] - public event EventHandler TextLengthChanged; - - /// <summary> - /// Is raised when one of the properties <see cref="Text"/>, <see cref="TextLength"/>, <see cref="LineCount"/>, - /// <see cref="UndoStack"/> changes. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event PropertyChangedEventHandler PropertyChanged; - - /// <summary> - /// Is raised before the document changes. - /// </summary> - /// <remarks> - /// <para>Here is the order in which events are raised during a document update:</para> - /// <list type="bullet"> - /// <item><description><b><see cref="BeginUpdate">BeginUpdate()</see></b></description> - /// <list type="bullet"> - /// <item><description>Start of change group (on undo stack)</description></item> - /// <item><description><see cref="UpdateStarted"/> event is raised</description></item> - /// </list></item> - /// <item><description><b><see cref="Insert(int,string)">Insert()</see> / <see cref="Remove(int,int)">Remove()</see> / <see cref="Replace(int,int,string)">Replace()</see></b></description> - /// <list type="bullet"> - /// <item><description><see cref="Changing"/> event is raised</description></item> - /// <item><description>The document is changed</description></item> - /// <item><description><see cref="TextAnchor.Deleted">TextAnchor.Deleted</see> event is raised if anchors were - /// in the deleted text portion</description></item> - /// <item><description><see cref="Changed"/> event is raised</description></item> - /// </list></item> - /// <item><description><b><see cref="EndUpdate">EndUpdate()</see></b></description> - /// <list type="bullet"> - /// <item><description><see cref="TextChanged"/> event is raised</description></item> - /// <item><description><see cref="PropertyChanged"/> event is raised (for the Text, TextLength, LineCount properties, in that order)</description></item> - /// <item><description>End of change group (on undo stack)</description></item> - /// <item><description><see cref="UpdateFinished"/> event is raised</description></item> - /// </list></item> - /// </list> - /// <para> - /// If the insert/remove/replace methods are called without a call to <c>BeginUpdate()</c>, - /// they will call <c>BeginUpdate()</c> and <c>EndUpdate()</c> to ensure no change happens outside of <c>UpdateStarted</c>/<c>UpdateFinished</c>. - /// </para><para> - /// There can be multiple document changes between the <c>BeginUpdate()</c> and <c>EndUpdate()</c> calls. - /// In this case, the events associated with EndUpdate will be raised only once after the whole document update is done. - /// </para><para> - /// The <see cref="UndoStack"/> listens to the <c>UpdateStarted</c> and <c>UpdateFinished</c> events to group all changes into a single undo step. - /// </para> - /// </remarks> - public event EventHandler<DocumentChangeEventArgs> Changing; - - /// <summary> - /// Is raised after the document has changed. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event EventHandler<DocumentChangeEventArgs> Changed; - - /// <summary> - /// Creates a snapshot of the current text. - /// </summary> - /// <remarks> - /// <para>This method returns an immutable snapshot of the document, and may be safely called even when - /// the document's owner thread is concurrently modifying the document. - /// </para><para> - /// This special thread-safety guarantee is valid only for TextDocument.CreateSnapshot(), not necessarily for other - /// classes implementing ITextSource.CreateSnapshot(). - /// </para><para> - /// </para> - /// </remarks> - public ITextSource CreateSnapshot() - { - lock (lockObject) - { - return new RopeTextSource(rope.Clone()); - } - } - - /// <summary> - /// Creates a snapshot of the current text. - /// Additionally, creates a checkpoint that allows tracking document changes. - /// </summary> - /// <remarks><inheritdoc cref="CreateSnapshot()"/><inheritdoc cref="ChangeTrackingCheckpoint"/></remarks> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", Justification = "Need to return snapshot and checkpoint together to ensure thread-safety")] - public ITextSource CreateSnapshot(out ChangeTrackingCheckpoint checkpoint) - { - lock (lockObject) - { - if (currentCheckpoint == null) - currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); - checkpoint = currentCheckpoint; - return new RopeTextSource(rope.Clone()); - } - } - - internal ChangeTrackingCheckpoint CreateChangeTrackingCheckpoint() - { - lock (lockObject) - { - if (currentCheckpoint == null) - currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); - return currentCheckpoint; - } - } - - /// <summary> - /// Creates a snapshot of a part of the current text. - /// </summary> - /// <remarks><inheritdoc cref="CreateSnapshot()"/></remarks> - public ITextSource CreateSnapshot(int offset, int length) - { - lock (lockObject) - { - return new RopeTextSource(rope.GetRange(offset, length)); - } - } - - /// <inheritdoc/> - public System.IO.TextReader CreateReader() - { - lock (lockObject) - { - return new RopeTextReader(rope); - } - } - #endregion - - #region BeginUpdate / EndUpdate - int beginUpdateCount; - - /// <summary> - /// Gets if an update is running. - /// </summary> - /// <remarks><inheritdoc cref="BeginUpdate"/></remarks> - public bool IsInUpdate - { - get - { - VerifyAccess(); - return beginUpdateCount > 0; - } - } - - /// <summary> - /// Immediately calls <see cref="BeginUpdate()"/>, - /// and returns an IDisposable that calls <see cref="EndUpdate()"/>. - /// </summary> - /// <remarks><inheritdoc cref="BeginUpdate"/></remarks> - public IDisposable RunUpdate() - { - BeginUpdate(); - return new CallbackOnDispose(EndUpdate); - } - - /// <summary> - /// <para>Begins a group of document changes.</para> - /// <para>Some events are suspended until EndUpdate is called, and the <see cref="UndoStack"/> will - /// group all changes into a single action.</para> - /// <para>Calling BeginUpdate several times increments a counter, only after the appropriate number - /// of EndUpdate calls the events resume their work.</para> - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public void BeginUpdate() - { - VerifyAccess(); - if (inDocumentChanging) - throw new InvalidOperationException("Cannot change document within another document change."); - beginUpdateCount++; - if (beginUpdateCount == 1) - { - undoStack.StartUndoGroup(); - if (UpdateStarted != null) - UpdateStarted(this, EventArgs.Empty); - } - } - - /// <summary> - /// Ends a group of document changes. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public void EndUpdate() - { - VerifyAccess(); - if (inDocumentChanging) - throw new InvalidOperationException("Cannot end update within document change."); - if (beginUpdateCount == 0) - throw new InvalidOperationException("No update is active."); - if (beginUpdateCount == 1) - { - // fire change events inside the change group - event handlers might add additional - // document changes to the change group - FireChangeEvents(); - undoStack.EndUndoGroup(); - beginUpdateCount = 0; - if (UpdateFinished != null) - UpdateFinished(this, EventArgs.Empty); - } - else - { - beginUpdateCount -= 1; - } - } - - /// <summary> - /// Occurs when a document change starts. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event EventHandler UpdateStarted; - - /// <summary> - /// Occurs when a document change is finished. - /// </summary> - /// <remarks><inheritdoc cref="Changing"/></remarks> - public event EventHandler UpdateFinished; - #endregion - - #region Fire events after update - int oldTextLength; - int oldLineCount; - bool fireTextChanged; - - /// <summary> - /// Fires TextChanged, TextLengthChanged, LineCountChanged if required. - /// </summary> - internal void FireChangeEvents() - { - // it may be necessary to fire the event multiple times if the document is changed - // from inside the event handlers - while (fireTextChanged) - { - fireTextChanged = false; - if (TextChanged != null) - TextChanged(this, EventArgs.Empty); - OnPropertyChanged("Text"); - - int textLength = rope.Length; - if (textLength != oldTextLength) - { - oldTextLength = textLength; - if (TextLengthChanged != null) - TextLengthChanged(this, EventArgs.Empty); - OnPropertyChanged("TextLength"); - } - int lineCount = lineTree.LineCount; - if (lineCount != oldLineCount) - { - oldLineCount = lineCount; - if (LineCountChanged != null) - LineCountChanged(this, EventArgs.Empty); - OnPropertyChanged("LineCount"); - } - } - } - - void OnPropertyChanged(string propertyName) - { - if (PropertyChanged != null) - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - #endregion - - #region Insert / Remove / Replace - /// <summary> - /// Inserts text. - /// </summary> - public void Insert(int offset, string text) - { - Replace(offset, 0, text); - } - - /// <summary> - /// Removes text. - /// </summary> - public void Remove(ISegment segment) - { - Replace(segment, string.Empty); - } - - /// <summary> - /// Removes text. - /// </summary> - public void Remove(int offset, int length) - { - Replace(offset, length, string.Empty); - } - - internal bool inDocumentChanging; - - /// <summary> - /// Replaces text. - /// </summary> - public void Replace(ISegment segment, string text) - { - if (segment == null) - throw new ArgumentNullException("segment"); - Replace(segment.Offset, segment.Length, text, null); - } - - /// <summary> - /// Replaces text. - /// </summary> - public void Replace(int offset, int length, string text) - { - Replace(offset, length, text, null); - } - - /// <summary> - /// Replaces text. - /// </summary> - /// <param name="offset">The starting offset of the text to be replaced.</param> - /// <param name="length">The length of the text to be replaced.</param> - /// <param name="text">The new text.</param> - /// <param name="offsetChangeMappingType">The offsetChangeMappingType determines how offsets inside the old text are mapped to the new text. - /// This affects how the anchors and segments inside the replaced region behave.</param> - public void Replace(int offset, int length, string text, OffsetChangeMappingType offsetChangeMappingType) - { - if (text == null) - throw new ArgumentNullException("text"); - // Please see OffsetChangeMappingType XML comments for details on how these modes work. - switch (offsetChangeMappingType) - { - case OffsetChangeMappingType.Normal: - Replace(offset, length, text, null); - break; - case OffsetChangeMappingType.KeepAnchorBeforeInsertion: - Replace(offset, length, text, OffsetChangeMap.FromSingleElement( - new OffsetChangeMapEntry(offset, length, text.Length, false, true))); - break; - case OffsetChangeMappingType.RemoveAndInsert: - if (length == 0 || text.Length == 0) - { - // only insertion or only removal? - // OffsetChangeMappingType doesn't matter, just use Normal. - Replace(offset, length, text, null); - } - else - { - OffsetChangeMap map = new OffsetChangeMap(2); - map.Add(new OffsetChangeMapEntry(offset, length, 0)); - map.Add(new OffsetChangeMapEntry(offset, 0, text.Length)); - map.Freeze(); - Replace(offset, length, text, map); - } - break; - case OffsetChangeMappingType.CharacterReplace: - if (length == 0 || text.Length == 0) - { - // only insertion or only removal? - // OffsetChangeMappingType doesn't matter, just use Normal. - Replace(offset, length, text, null); - } - else if (text.Length > length) - { - // look at OffsetChangeMappingType.CharacterReplace XML comments on why we need to replace - // the last character - OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + length - 1, 1, 1 + text.Length - length); - Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry)); - } - else if (text.Length < length) - { - OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + text.Length, length - text.Length, 0, true, false); - Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry)); - } - else - { - Replace(offset, length, text, OffsetChangeMap.Empty); - } - break; - default: - throw new ArgumentOutOfRangeException("offsetChangeMappingType", offsetChangeMappingType, "Invalid enum value"); - } - } - - /// <summary> - /// Replaces text. - /// </summary> - /// <param name="offset">The starting offset of the text to be replaced.</param> - /// <param name="length">The length of the text to be replaced.</param> - /// <param name="text">The new text.</param> - /// <param name="offsetChangeMap">The offsetChangeMap determines how offsets inside the old text are mapped to the new text. - /// This affects how the anchors and segments inside the replaced region behave. - /// If you pass null (the default when using one of the other overloads), the offsets are changed as - /// in OffsetChangeMappingType.Normal mode. - /// If you pass OffsetChangeMap.Empty, then everything will stay in its old place (OffsetChangeMappingType.CharacterReplace mode). - /// The offsetChangeMap must be a valid 'explanation' for the document change. See <see cref="OffsetChangeMap.IsValidForDocumentChange"/>. - /// Passing an OffsetChangeMap to the Replace method will automatically freeze it to ensure the thread safety of the resulting - /// DocumentChangeEventArgs instance. - /// </param> - public void Replace(int offset, int length, string text, OffsetChangeMap offsetChangeMap) - { - if (text == null) - throw new ArgumentNullException("text"); - - if (offsetChangeMap != null) - offsetChangeMap.Freeze(); - - // Ensure that all changes take place inside an update group. - // Will also take care of throwing an exception if inDocumentChanging is set. - BeginUpdate(); - try - { - // protect document change against corruption by other changes inside the event handlers - inDocumentChanging = true; - try - { - // The range verification must wait until after the BeginUpdate() call because the document - // might be modified inside the UpdateStarted event. - ThrowIfRangeInvalid(offset, length); - - DoReplace(offset, length, text, offsetChangeMap); - } - finally - { - inDocumentChanging = false; - } - } - finally - { - EndUpdate(); - } - } - - void DoReplace(int offset, int length, string newText, OffsetChangeMap offsetChangeMap) - { - if (length == 0 && newText.Length == 0) - return; - - // trying to replace a single character in 'Normal' mode? - // for single characters, 'CharacterReplace' mode is equivalent, but more performant - // (we don't have to touch the anchorTree at all in 'CharacterReplace' mode) - if (length == 1 && newText.Length == 1 && offsetChangeMap == null) - offsetChangeMap = OffsetChangeMap.Empty; - - string removedText = rope.ToString(offset, length); - DocumentChangeEventArgs args = new DocumentChangeEventArgs(offset, removedText, newText, offsetChangeMap); - - // fire DocumentChanging event - if (Changing != null) - Changing(this, args); - - undoStack.Push(this, args); - - cachedText = null; // reset cache of complete document text - fireTextChanged = true; - DelayedEvents delayedEvents = new DelayedEvents(); - - lock (lockObject) - { - // create linked list of checkpoints, if required - if (currentCheckpoint != null) - { - currentCheckpoint = currentCheckpoint.Append(args); - } - - // now update the textBuffer and lineTree - if (offset == 0 && length == rope.Length) - { - // optimize replacing the whole document - rope.Clear(); - rope.InsertText(0, newText); - lineManager.Rebuild(); - } - else - { - rope.RemoveRange(offset, length); - lineManager.Remove(offset, length); -#if DEBUG - lineTree.CheckProperties(); -#endif - rope.InsertText(offset, newText); - lineManager.Insert(offset, newText); -#if DEBUG - lineTree.CheckProperties(); -#endif - } - } - - // update text anchors - if (offsetChangeMap == null) - { - anchorTree.HandleTextChange(args.CreateSingleChangeMapEntry(), delayedEvents); - } - else - { - foreach (OffsetChangeMapEntry entry in offsetChangeMap) - { - anchorTree.HandleTextChange(entry, delayedEvents); - } - } - - // raise delayed events after our data structures are consistent again - delayedEvents.RaiseEvents(); - - // fire DocumentChanged event - if (Changed != null) - Changed(this, args); - } - #endregion - - #region GetLineBy... - /// <summary> - /// Gets a read-only list of lines. - /// </summary> - /// <remarks><inheritdoc cref="DocumentLine"/></remarks> - public IList<DocumentLine> Lines - { - get { return lineTree; } - } - - /// <summary> - /// Gets a line by the line number: O(log n) - /// </summary> - public DocumentLine GetLineByNumber(int number) - { - VerifyAccess(); - if (number < 1 || number > lineTree.LineCount) - throw new ArgumentOutOfRangeException("number", number, "Value must be between 1 and " + lineTree.LineCount); - return lineTree.GetByNumber(number); - } - - /// <summary> - /// Gets a document lines by offset. - /// Runtime: O(log n) - /// </summary> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")] - public DocumentLine GetLineByOffset(int offset) - { - VerifyAccess(); - if (offset < 0 || offset > rope.Length) - { - throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString()); - } - return lineTree.GetByOffset(offset); - } - #endregion - - /// <summary> - /// Gets the offset from a text location. - /// </summary> - /// <seealso cref="GetLocation"/> - public int GetOffset(TextLocation location) - { - return GetOffset(location.Line, location.Column); - } - - /// <summary> - /// Gets the offset from a text location. - /// </summary> - /// <seealso cref="GetLocation"/> - public int GetOffset(int line, int column) - { - DocumentLine docLine = GetLineByNumber(line); - if (column <= 0) - return docLine.Offset; - if (column > docLine.Length) - return docLine.EndOffset; - return docLine.Offset + column - 1; - } - - /// <summary> - /// Gets the location from an offset. - /// </summary> - /// <seealso cref="GetOffset(TextLocation)"/> - public TextLocation GetLocation(int offset) - { - DocumentLine line = GetLineByOffset(offset); - return new TextLocation(line.LineNumber, offset - line.Offset + 1); - } - - readonly ObservableCollection<ILineTracker> lineTrackers = new ObservableCollection<ILineTracker>(); - - /// <summary> - /// Gets the list of <see cref="ILineTracker"/>s attached to this document. - /// You can add custom line trackers to this list. - /// </summary> - public IList<ILineTracker> LineTrackers - { - get - { - VerifyAccess(); - return lineTrackers; - } - } - - UndoStack undoStack; - - /// <summary> - /// Gets the <see cref="UndoStack"/> of the document. - /// </summary> - /// <remarks>This property can also be used to set the undo stack, e.g. for sharing a common undo stack between multiple documents.</remarks> - public UndoStack UndoStack - { - get { return undoStack; } - set - { - if (value == null) - throw new ArgumentNullException(); - if (value != undoStack) - { - undoStack.ClearAll(); // first clear old undo stack, so that it can't be used to perform unexpected changes on this document - // ClearAll() will also throw an exception when it's not safe to replace the undo stack (e.g. update is currently in progress) - undoStack = value; - OnPropertyChanged("UndoStack"); - } - } - } - - /// <summary> - /// Creates a new <see cref="TextAnchor"/> at the specified offset. - /// </summary> - /// <inheritdoc cref="TextAnchor" select="remarks|example"/> - public TextAnchor CreateAnchor(int offset) - { - VerifyAccess(); - if (offset < 0 || offset > rope.Length) - { - throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); - } - return anchorTree.CreateAnchor(offset); - } - - #region LineCount - /// <summary> - /// Gets the total number of lines in the document. - /// Runtime: O(1). - /// </summary> - public int LineCount - { - get - { - VerifyAccess(); - return lineTree.LineCount; - } - } - - /// <summary> - /// Is raised when the LineCount property changes. - /// </summary> - [Obsolete("This event will be removed in a future version; use the PropertyChanged event instead")] - public event EventHandler LineCountChanged; - #endregion - - #region Debugging - [Conditional("DEBUG")] - internal void DebugVerifyAccess() - { - VerifyAccess(); - } - - /// <summary> - /// Gets the document lines tree in string form. - /// </summary> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - internal string GetLineTreeAsString() - { -#if DEBUG - return lineTree.GetTreeAsString(); -#else + /// <summary> + /// This class is the main class of the text model. Basically, it is a <see cref="System.Text.StringBuilder"/> with events. + /// </summary> + /// <remarks> + /// <b>Thread safety:</b> + /// <inheritdoc cref="VerifyAccess"/> + /// <para>However, there is a single method that is thread-safe: <see cref="CreateSnapshot()"/> (and its overloads).</para> + /// </remarks> + public sealed class TextDocument : ITextSource, INotifyPropertyChanged + { + #region Thread ownership + readonly object lockObject = new object(); + Thread owner = Thread.CurrentThread; + + /// <summary> + /// Verifies that the current thread is the documents owner thread. + /// Throws an <see cref="InvalidOperationException"/> if the wrong thread accesses the TextDocument. + /// </summary> + /// <remarks> + /// <para>The TextDocument class is not thread-safe. A document instance expects to have a single owner thread + /// and will throw an <see cref="InvalidOperationException"/> when accessed from another thread. + /// It is possible to change the owner thread using the <see cref="SetOwnerThread"/> method.</para> + /// </remarks> + public void VerifyAccess() + { + if (Thread.CurrentThread != owner) + throw new InvalidOperationException("TextDocument can be accessed only from the thread that owns it."); + } + + /// <summary> + /// Transfers ownership of the document to another thread. This method can be used to load + /// a file into a TextDocument on a background thread and then transfer ownership to the UI thread + /// for displaying the document. + /// </summary> + /// <remarks> + /// <inheritdoc cref="VerifyAccess"/> + /// <para> + /// The owner can be set to null, which means that no thread can access the document. But, if the document + /// has no owner thread, any thread may take ownership by calling <see cref="SetOwnerThread"/>. + /// </para> + /// </remarks> + public void SetOwnerThread(Thread newOwner) + { + // We need to lock here to ensure that in the null owner case, + // only one thread succeeds in taking ownership. + lock (lockObject) { + if (owner != null) { + VerifyAccess(); + } + owner = newOwner; + } + } + #endregion + + #region Fields + Constructor + readonly Rope<char> rope; + readonly DocumentLineTree lineTree; + readonly LineManager lineManager; + readonly TextAnchorTree anchorTree; + ChangeTrackingCheckpoint currentCheckpoint; + + /// <summary> + /// Create an empty text document. + /// </summary> + public TextDocument() + : this(string.Empty) + { + } + + /// <summary> + /// Create a new text document with the specified initial text. + /// </summary> + public TextDocument(IEnumerable<char> initialText) + { + if (initialText == null) + throw new ArgumentNullException("initialText"); + rope = new Rope<char>(initialText); + lineTree = new DocumentLineTree(this); + lineManager = new LineManager(lineTree, this); + lineTrackers.CollectionChanged += delegate { + lineManager.UpdateListOfLineTrackers(); + }; + + anchorTree = new TextAnchorTree(this); + undoStack = new UndoStack(); + FireChangeEvents(); + } + + /// <summary> + /// Create a new text document with the specified initial text. + /// </summary> + public TextDocument(ITextSource initialText) + : this(GetTextFromTextSource(initialText)) + { + } + + // gets the text from a text source, directly retrieving the underlying rope where possible + static IEnumerable<char> GetTextFromTextSource(ITextSource textSource) + { + if (textSource == null) + throw new ArgumentNullException("textSource"); + + RopeTextSource rts = textSource as RopeTextSource; + if (rts != null) + return rts.GetRope(); + + TextDocument doc = textSource as TextDocument; + if (doc != null) + return doc.rope; + + return textSource.Text; + } + #endregion + + #region Text + void ThrowIfRangeInvalid(int offset, int length) + { + if (offset < 0 || offset > rope.Length) { + throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); + } + if (length < 0 || offset + length > rope.Length) { + throw new ArgumentOutOfRangeException("length", length, "0 <= length, offset(" + offset + ")+length <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); + } + } + + /// <inheritdoc/> + public string GetText(int offset, int length) + { + VerifyAccess(); + return rope.ToString(offset, length); + } + + /// <summary> + /// Retrieves the text for a portion of the document. + /// </summary> + public string GetText(ISegment segment) + { + if (segment == null) + throw new ArgumentNullException("segment"); + return GetText(segment.Offset, segment.Length); + } + + int ITextSource.IndexOfAny(char[] anyOf, int startIndex, int count) + { + DebugVerifyAccess(); // frequently called (NewLineFinder), so must be fast in release builds + return rope.IndexOfAny(anyOf, startIndex, count); + } + + /// <inheritdoc/> + public char GetCharAt(int offset) + { + DebugVerifyAccess(); // frequently called, so must be fast in release builds + return rope[offset]; + } + + WeakReference cachedText; + + /// <summary> + /// Gets/Sets the text of the whole document. + /// </summary> + public string Text { + get { + VerifyAccess(); + string completeText = cachedText != null ? (cachedText.Target as string) : null; + if (completeText == null) { + completeText = rope.ToString(); + cachedText = new WeakReference(completeText); + } + return completeText; + } + set { + VerifyAccess(); + if (value == null) + throw new ArgumentNullException("value"); + Replace(0, rope.Length, value); + } + } + + /// <inheritdoc/> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event EventHandler TextChanged; + + /// <inheritdoc/> + public int TextLength { + get { + VerifyAccess(); + return rope.Length; + } + } + + /// <summary> + /// Is raised when the TextLength property changes. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + [Obsolete("This event will be removed in a future version; use the PropertyChanged event instead")] + public event EventHandler TextLengthChanged; + + /// <summary> + /// Is raised when one of the properties <see cref="Text"/>, <see cref="TextLength"/>, <see cref="LineCount"/>, + /// <see cref="UndoStack"/> changes. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event PropertyChangedEventHandler PropertyChanged; + + /// <summary> + /// Is raised before the document changes. + /// </summary> + /// <remarks> + /// <para>Here is the order in which events are raised during a document update:</para> + /// <list type="bullet"> + /// <item><description><b><see cref="BeginUpdate">BeginUpdate()</see></b></description> + /// <list type="bullet"> + /// <item><description>Start of change group (on undo stack)</description></item> + /// <item><description><see cref="UpdateStarted"/> event is raised</description></item> + /// </list></item> + /// <item><description><b><see cref="Insert(int,string)">Insert()</see> / <see cref="Remove(int,int)">Remove()</see> / <see cref="Replace(int,int,string)">Replace()</see></b></description> + /// <list type="bullet"> + /// <item><description><see cref="Changing"/> event is raised</description></item> + /// <item><description>The document is changed</description></item> + /// <item><description><see cref="TextAnchor.Deleted">TextAnchor.Deleted</see> event is raised if anchors were + /// in the deleted text portion</description></item> + /// <item><description><see cref="Changed"/> event is raised</description></item> + /// </list></item> + /// <item><description><b><see cref="EndUpdate">EndUpdate()</see></b></description> + /// <list type="bullet"> + /// <item><description><see cref="TextChanged"/> event is raised</description></item> + /// <item><description><see cref="PropertyChanged"/> event is raised (for the Text, TextLength, LineCount properties, in that order)</description></item> + /// <item><description>End of change group (on undo stack)</description></item> + /// <item><description><see cref="UpdateFinished"/> event is raised</description></item> + /// </list></item> + /// </list> + /// <para> + /// If the insert/remove/replace methods are called without a call to <c>BeginUpdate()</c>, + /// they will call <c>BeginUpdate()</c> and <c>EndUpdate()</c> to ensure no change happens outside of <c>UpdateStarted</c>/<c>UpdateFinished</c>. + /// </para><para> + /// There can be multiple document changes between the <c>BeginUpdate()</c> and <c>EndUpdate()</c> calls. + /// In this case, the events associated with EndUpdate will be raised only once after the whole document update is done. + /// </para><para> + /// The <see cref="UndoStack"/> listens to the <c>UpdateStarted</c> and <c>UpdateFinished</c> events to group all changes into a single undo step. + /// </para> + /// </remarks> + public event EventHandler<DocumentChangeEventArgs> Changing; + + /// <summary> + /// Is raised after the document has changed. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event EventHandler<DocumentChangeEventArgs> Changed; + + /// <summary> + /// Creates a snapshot of the current text. + /// </summary> + /// <remarks> + /// <para>This method returns an immutable snapshot of the document, and may be safely called even when + /// the document's owner thread is concurrently modifying the document. + /// </para><para> + /// This special thread-safety guarantee is valid only for TextDocument.CreateSnapshot(), not necessarily for other + /// classes implementing ITextSource.CreateSnapshot(). + /// </para><para> + /// </para> + /// </remarks> + public ITextSource CreateSnapshot() + { + lock (lockObject) { + return new RopeTextSource(rope.Clone()); + } + } + + /// <summary> + /// Creates a snapshot of the current text. + /// Additionally, creates a checkpoint that allows tracking document changes. + /// </summary> + /// <remarks><inheritdoc cref="CreateSnapshot()"/><inheritdoc cref="ChangeTrackingCheckpoint"/></remarks> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", Justification = "Need to return snapshot and checkpoint together to ensure thread-safety")] + public ITextSource CreateSnapshot(out ChangeTrackingCheckpoint checkpoint) + { + lock (lockObject) { + if (currentCheckpoint == null) + currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); + checkpoint = currentCheckpoint; + return new RopeTextSource(rope.Clone()); + } + } + + internal ChangeTrackingCheckpoint CreateChangeTrackingCheckpoint() + { + lock (lockObject) { + if (currentCheckpoint == null) + currentCheckpoint = new ChangeTrackingCheckpoint(lockObject); + return currentCheckpoint; + } + } + + /// <summary> + /// Creates a snapshot of a part of the current text. + /// </summary> + /// <remarks><inheritdoc cref="CreateSnapshot()"/></remarks> + public ITextSource CreateSnapshot(int offset, int length) + { + lock (lockObject) { + return new RopeTextSource(rope.GetRange(offset, length)); + } + } + + /// <inheritdoc/> + public System.IO.TextReader CreateReader() + { + lock (lockObject) { + return new RopeTextReader(rope); + } + } + #endregion + + #region BeginUpdate / EndUpdate + int beginUpdateCount; + + /// <summary> + /// Gets if an update is running. + /// </summary> + /// <remarks><inheritdoc cref="BeginUpdate"/></remarks> + public bool IsInUpdate { + get { + VerifyAccess(); + return beginUpdateCount > 0; + } + } + + /// <summary> + /// Immediately calls <see cref="BeginUpdate()"/>, + /// and returns an IDisposable that calls <see cref="EndUpdate()"/>. + /// </summary> + /// <remarks><inheritdoc cref="BeginUpdate"/></remarks> + public IDisposable RunUpdate() + { + BeginUpdate(); + return new CallbackOnDispose(EndUpdate); + } + + /// <summary> + /// <para>Begins a group of document changes.</para> + /// <para>Some events are suspended until EndUpdate is called, and the <see cref="UndoStack"/> will + /// group all changes into a single action.</para> + /// <para>Calling BeginUpdate several times increments a counter, only after the appropriate number + /// of EndUpdate calls the events resume their work.</para> + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public void BeginUpdate() + { + VerifyAccess(); + if (inDocumentChanging) + throw new InvalidOperationException("Cannot change document within another document change."); + beginUpdateCount++; + if (beginUpdateCount == 1) { + undoStack.StartUndoGroup(); + if (UpdateStarted != null) + UpdateStarted(this, EventArgs.Empty); + } + } + + /// <summary> + /// Ends a group of document changes. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public void EndUpdate() + { + VerifyAccess(); + if (inDocumentChanging) + throw new InvalidOperationException("Cannot end update within document change."); + if (beginUpdateCount == 0) + throw new InvalidOperationException("No update is active."); + if (beginUpdateCount == 1) { + // fire change events inside the change group - event handlers might add additional + // document changes to the change group + FireChangeEvents(); + undoStack.EndUndoGroup(); + beginUpdateCount = 0; + if (UpdateFinished != null) + UpdateFinished(this, EventArgs.Empty); + } else { + beginUpdateCount -= 1; + } + } + + /// <summary> + /// Occurs when a document change starts. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event EventHandler UpdateStarted; + + /// <summary> + /// Occurs when a document change is finished. + /// </summary> + /// <remarks><inheritdoc cref="Changing"/></remarks> + public event EventHandler UpdateFinished; + #endregion + + #region Fire events after update + int oldTextLength; + int oldLineCount; + bool fireTextChanged; + + /// <summary> + /// Fires TextChanged, TextLengthChanged, LineCountChanged if required. + /// </summary> + internal void FireChangeEvents() + { + // it may be necessary to fire the event multiple times if the document is changed + // from inside the event handlers + while (fireTextChanged) { + fireTextChanged = false; + if (TextChanged != null) + TextChanged(this, EventArgs.Empty); + OnPropertyChanged("Text"); + + int textLength = rope.Length; + if (textLength != oldTextLength) { + oldTextLength = textLength; + if (TextLengthChanged != null) + TextLengthChanged(this, EventArgs.Empty); + OnPropertyChanged("TextLength"); + } + int lineCount = lineTree.LineCount; + if (lineCount != oldLineCount) { + oldLineCount = lineCount; + if (LineCountChanged != null) + LineCountChanged(this, EventArgs.Empty); + OnPropertyChanged("LineCount"); + } + } + } + + void OnPropertyChanged(string propertyName) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + #endregion + + #region Insert / Remove / Replace + /// <summary> + /// Inserts text. + /// </summary> + public void Insert(int offset, string text) + { + Replace(offset, 0, text); + } + + /// <summary> + /// Removes text. + /// </summary> + public void Remove(ISegment segment) + { + Replace(segment, string.Empty); + } + + /// <summary> + /// Removes text. + /// </summary> + public void Remove(int offset, int length) + { + Replace(offset, length, string.Empty); + } + + internal bool inDocumentChanging; + + /// <summary> + /// Replaces text. + /// </summary> + public void Replace(ISegment segment, string text) + { + if (segment == null) + throw new ArgumentNullException("segment"); + Replace(segment.Offset, segment.Length, text, null); + } + + /// <summary> + /// Replaces text. + /// </summary> + public void Replace(int offset, int length, string text) + { + Replace(offset, length, text, null); + } + + /// <summary> + /// Replaces text. + /// </summary> + /// <param name="offset">The starting offset of the text to be replaced.</param> + /// <param name="length">The length of the text to be replaced.</param> + /// <param name="text">The new text.</param> + /// <param name="offsetChangeMappingType">The offsetChangeMappingType determines how offsets inside the old text are mapped to the new text. + /// This affects how the anchors and segments inside the replaced region behave.</param> + public void Replace(int offset, int length, string text, OffsetChangeMappingType offsetChangeMappingType) + { + if (text == null) + throw new ArgumentNullException("text"); + // Please see OffsetChangeMappingType XML comments for details on how these modes work. + switch (offsetChangeMappingType) { + case OffsetChangeMappingType.Normal: + Replace(offset, length, text, null); + break; + case OffsetChangeMappingType.KeepAnchorBeforeInsertion: + Replace(offset, length, text, OffsetChangeMap.FromSingleElement( + new OffsetChangeMapEntry(offset, length, text.Length, false, true))); + break; + case OffsetChangeMappingType.RemoveAndInsert: + if (length == 0 || text.Length == 0) { + // only insertion or only removal? + // OffsetChangeMappingType doesn't matter, just use Normal. + Replace(offset, length, text, null); + } else { + OffsetChangeMap map = new OffsetChangeMap(2); + map.Add(new OffsetChangeMapEntry(offset, length, 0)); + map.Add(new OffsetChangeMapEntry(offset, 0, text.Length)); + map.Freeze(); + Replace(offset, length, text, map); + } + break; + case OffsetChangeMappingType.CharacterReplace: + if (length == 0 || text.Length == 0) { + // only insertion or only removal? + // OffsetChangeMappingType doesn't matter, just use Normal. + Replace(offset, length, text, null); + } else if (text.Length > length) { + // look at OffsetChangeMappingType.CharacterReplace XML comments on why we need to replace + // the last character + OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + length - 1, 1, 1 + text.Length - length); + Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry)); + } else if (text.Length < length) { + OffsetChangeMapEntry entry = new OffsetChangeMapEntry(offset + text.Length, length - text.Length, 0, true, false); + Replace(offset, length, text, OffsetChangeMap.FromSingleElement(entry)); + } else { + Replace(offset, length, text, OffsetChangeMap.Empty); + } + break; + default: + throw new ArgumentOutOfRangeException("offsetChangeMappingType", offsetChangeMappingType, "Invalid enum value"); + } + } + + /// <summary> + /// Replaces text. + /// </summary> + /// <param name="offset">The starting offset of the text to be replaced.</param> + /// <param name="length">The length of the text to be replaced.</param> + /// <param name="text">The new text.</param> + /// <param name="offsetChangeMap">The offsetChangeMap determines how offsets inside the old text are mapped to the new text. + /// This affects how the anchors and segments inside the replaced region behave. + /// If you pass null (the default when using one of the other overloads), the offsets are changed as + /// in OffsetChangeMappingType.Normal mode. + /// If you pass OffsetChangeMap.Empty, then everything will stay in its old place (OffsetChangeMappingType.CharacterReplace mode). + /// The offsetChangeMap must be a valid 'explanation' for the document change. See <see cref="OffsetChangeMap.IsValidForDocumentChange"/>. + /// Passing an OffsetChangeMap to the Replace method will automatically freeze it to ensure the thread safety of the resulting + /// DocumentChangeEventArgs instance. + /// </param> + public void Replace(int offset, int length, string text, OffsetChangeMap offsetChangeMap) + { + if (text == null) + throw new ArgumentNullException("text"); + + if (offsetChangeMap != null) + offsetChangeMap.Freeze(); + + // Ensure that all changes take place inside an update group. + // Will also take care of throwing an exception if inDocumentChanging is set. + BeginUpdate(); + try { + // protect document change against corruption by other changes inside the event handlers + inDocumentChanging = true; + try { + // The range verification must wait until after the BeginUpdate() call because the document + // might be modified inside the UpdateStarted event. + ThrowIfRangeInvalid(offset, length); + + DoReplace(offset, length, text, offsetChangeMap); + } finally { + inDocumentChanging = false; + } + } finally { + EndUpdate(); + } + } + + void DoReplace(int offset, int length, string newText, OffsetChangeMap offsetChangeMap) + { + if (length == 0 && newText.Length == 0) + return; + + // trying to replace a single character in 'Normal' mode? + // for single characters, 'CharacterReplace' mode is equivalent, but more performant + // (we don't have to touch the anchorTree at all in 'CharacterReplace' mode) + if (length == 1 && newText.Length == 1 && offsetChangeMap == null) + offsetChangeMap = OffsetChangeMap.Empty; + + string removedText = rope.ToString(offset, length); + DocumentChangeEventArgs args = new DocumentChangeEventArgs(offset, removedText, newText, offsetChangeMap); + + // fire DocumentChanging event + if (Changing != null) + Changing(this, args); + + undoStack.Push(this, args); + + cachedText = null; // reset cache of complete document text + fireTextChanged = true; + DelayedEvents delayedEvents = new DelayedEvents(); + + lock (lockObject) { + // create linked list of checkpoints, if required + if (currentCheckpoint != null) { + currentCheckpoint = currentCheckpoint.Append(args); + } + + // now update the textBuffer and lineTree + if (offset == 0 && length == rope.Length) { + // optimize replacing the whole document + rope.Clear(); + rope.InsertText(0, newText); + lineManager.Rebuild(); + } else { + rope.RemoveRange(offset, length); + lineManager.Remove(offset, length); + #if DEBUG + lineTree.CheckProperties(); + #endif + rope.InsertText(offset, newText); + lineManager.Insert(offset, newText); + #if DEBUG + lineTree.CheckProperties(); + #endif + } + } + + // update text anchors + if (offsetChangeMap == null) { + anchorTree.HandleTextChange(args.CreateSingleChangeMapEntry(), delayedEvents); + } else { + foreach (OffsetChangeMapEntry entry in offsetChangeMap) { + anchorTree.HandleTextChange(entry, delayedEvents); + } + } + + // raise delayed events after our data structures are consistent again + delayedEvents.RaiseEvents(); + + // fire DocumentChanged event + if (Changed != null) + Changed(this, args); + } + #endregion + + #region GetLineBy... + /// <summary> + /// Gets a read-only list of lines. + /// </summary> + /// <remarks><inheritdoc cref="DocumentLine"/></remarks> + public IList<DocumentLine> Lines { + get { return lineTree; } + } + + /// <summary> + /// Gets a line by the line number: O(log n) + /// </summary> + public DocumentLine GetLineByNumber(int number) + { + VerifyAccess(); + if (number < 1 || number > lineTree.LineCount) + throw new ArgumentOutOfRangeException("number", number, "Value must be between 1 and " + lineTree.LineCount); + return lineTree.GetByNumber(number); + } + + /// <summary> + /// Gets a document lines by offset. + /// Runtime: O(log n) + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")] + public DocumentLine GetLineByOffset(int offset) + { + VerifyAccess(); + if (offset < 0 || offset > rope.Length) { + throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString()); + } + return lineTree.GetByOffset(offset); + } + #endregion + + /// <summary> + /// Gets the offset from a text location. + /// </summary> + /// <seealso cref="GetLocation"/> + public int GetOffset(TextLocation location) + { + return GetOffset(location.Line, location.Column); + } + + /// <summary> + /// Gets the offset from a text location. + /// </summary> + /// <seealso cref="GetLocation"/> + public int GetOffset(int line, int column) + { + DocumentLine docLine = GetLineByNumber(line); + if (column <= 0) + return docLine.Offset; + if (column > docLine.Length) + return docLine.EndOffset; + return docLine.Offset + column - 1; + } + + /// <summary> + /// Gets the location from an offset. + /// </summary> + /// <seealso cref="GetOffset(TextLocation)"/> + public TextLocation GetLocation(int offset) + { + DocumentLine line = GetLineByOffset(offset); + return new TextLocation(line.LineNumber, offset - line.Offset + 1); + } + + readonly ObservableCollection<ILineTracker> lineTrackers = new ObservableCollection<ILineTracker>(); + + /// <summary> + /// Gets the list of <see cref="ILineTracker"/>s attached to this document. + /// You can add custom line trackers to this list. + /// </summary> + public IList<ILineTracker> LineTrackers { + get { + VerifyAccess(); + return lineTrackers; + } + } + + UndoStack undoStack; + + /// <summary> + /// Gets the <see cref="UndoStack"/> of the document. + /// </summary> + /// <remarks>This property can also be used to set the undo stack, e.g. for sharing a common undo stack between multiple documents.</remarks> + public UndoStack UndoStack { + get { return undoStack; } + set { + if (value == null) + throw new ArgumentNullException(); + if (value != undoStack) { + undoStack.ClearAll(); // first clear old undo stack, so that it can't be used to perform unexpected changes on this document + // ClearAll() will also throw an exception when it's not safe to replace the undo stack (e.g. update is currently in progress) + undoStack = value; + OnPropertyChanged("UndoStack"); + } + } + } + + /// <summary> + /// Creates a new <see cref="TextAnchor"/> at the specified offset. + /// </summary> + /// <inheritdoc cref="TextAnchor" select="remarks|example"/> + public TextAnchor CreateAnchor(int offset) + { + VerifyAccess(); + if (offset < 0 || offset > rope.Length) { + throw new ArgumentOutOfRangeException("offset", offset, "0 <= offset <= " + rope.Length.ToString(CultureInfo.InvariantCulture)); + } + return anchorTree.CreateAnchor(offset); + } + + #region LineCount + /// <summary> + /// Gets the total number of lines in the document. + /// Runtime: O(1). + /// </summary> + public int LineCount { + get { + VerifyAccess(); + return lineTree.LineCount; + } + } + + /// <summary> + /// Is raised when the LineCount property changes. + /// </summary> + [Obsolete("This event will be removed in a future version; use the PropertyChanged event instead")] + public event EventHandler LineCountChanged; + #endregion + + #region Debugging + [Conditional("DEBUG")] + internal void DebugVerifyAccess() + { + VerifyAccess(); + } + + /// <summary> + /// Gets the document lines tree in string form. + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + internal string GetLineTreeAsString() + { + #if DEBUG + return lineTree.GetTreeAsString(); + #else return "Not available in release build."; -#endif - } - - /// <summary> - /// Gets the text anchor tree in string form. - /// </summary> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - internal string GetTextAnchorTreeAsString() - { -#if DEBUG - return anchorTree.GetTreeAsString(); -#else + #endif + } + + /// <summary> + /// Gets the text anchor tree in string form. + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + internal string GetTextAnchorTreeAsString() + { + #if DEBUG + return anchorTree.GetTreeAsString(); + #else return "Not available in release build."; -#endif - } - #endregion - } + #endif + } + #endregion + } } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/UndoStack.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/UndoStack.cs index 86e1fa33e..f0a759b23 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/UndoStack.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Document/UndoStack.cs @@ -414,7 +414,7 @@ namespace Tango.Scripting.Editors.Document /// </summary> public void ClearAll() { - //ThrowIfUndoGroupOpen(); + ThrowIfUndoGroupOpen(); actionCountInUndoGroup = 0; optionalActionCount = 0; if (undostack.Count != 0) { diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs deleted file mode 100644 index e566e6aa9..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Editing/BreakPointMargin.cs +++ /dev/null @@ -1,285 +0,0 @@ -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/Errors/ITextMarker.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/ITextMarker.cs deleted file mode 100644 index dcbf8388a..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/ITextMarker.cs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Windows; -using System.Windows.Media; - -namespace Tango.Scripting.Editors -{ - /// <summary> - /// Represents a text marker. - /// </summary> - public interface ITextMarker - { - /// <summary> - /// Gets the start offset of the marked text region. - /// </summary> - int StartOffset { get; } - - /// <summary> - /// Gets the end offset of the marked text region. - /// </summary> - int EndOffset { get; } - - /// <summary> - /// Gets the length of the marked region. - /// </summary> - int Length { get; } - - /// <summary> - /// Deletes the text marker. - /// </summary> - void Delete(); - - /// <summary> - /// Gets whether the text marker was deleted. - /// </summary> - bool IsDeleted { get; } - - /// <summary> - /// Event that occurs when the text marker is deleted. - /// </summary> - event EventHandler Deleted; - - /// <summary> - /// Gets/Sets the background color. - /// </summary> - Color? BackgroundColor { get; set; } - - /// <summary> - /// Gets/Sets the foreground color. - /// </summary> - Color? ForegroundColor { get; set; } - - /// <summary> - /// Gets/Sets the font weight. - /// </summary> - FontWeight? FontWeight { get; set; } - - /// <summary> - /// Gets/Sets the font style. - /// </summary> - FontStyle? FontStyle { get; set; } - - /// <summary> - /// Gets/Sets the type of the marker. Use TextMarkerType.None for normal markers. - /// </summary> - TextMarkerTypes MarkerTypes { get; set; } - - /// <summary> - /// Gets/Sets the color of the marker. - /// </summary> - Color MarkerColor { get; set; } - - /// <summary> - /// Gets/Sets an object with additional data for this text marker. - /// </summary> - object Tag { get; set; } - - /// <summary> - /// Gets/Sets an object that will be displayed as tooltip in the text editor. - /// </summary> - /// <remarks>Not supported in this sample!</remarks> - object ToolTip { get; set; } - } - - [Flags] - public enum TextMarkerTypes - { - /// <summary> - /// Use no marker - /// </summary> - None = 0x0000, - /// <summary> - /// Use squiggly underline marker - /// </summary> - SquigglyUnderline = 0x001, - /// <summary> - /// Normal underline. - /// </summary> - NormalUnderline = 0x002, - /// <summary> - /// Dotted underline. - /// </summary> - DottedUnderline = 0x004, - - /// <summary> - /// Horizontal line in the scroll bar. - /// </summary> - LineInScrollBar = 0x0100, - /// <summary> - /// Small triangle in the scroll bar, pointing to the right. - /// </summary> - ScrollBarRightTriangle = 0x0400, - /// <summary> - /// Small triangle in the scroll bar, pointing to the left. - /// </summary> - ScrollBarLeftTriangle = 0x0800, - /// <summary> - /// Small circle in the scroll bar. - /// </summary> - CircleInScrollBar = 0x1000 - } - - public interface ITextMarkerService - { - /// <summary> - /// Creates a new text marker. The text marker will be invisible at first, - /// you need to set one of the Color properties to make it visible. - /// </summary> - ITextMarker Create(int startOffset, int length); - - /// <summary> - /// Gets the list of text markers. - /// </summary> - IEnumerable<ITextMarker> TextMarkers { get; } - - /// <summary> - /// Removes the specified text marker. - /// </summary> - void Remove(ITextMarker marker); - - /// <summary> - /// Removes all text markers that match the condition. - /// </summary> - void RemoveAll(Predicate<ITextMarker> predicate); - - /// <summary> - /// Finds all text markers at the specified offset. - /// </summary> - IEnumerable<ITextMarker> GetMarkersAtOffset(int offset); - } -} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/TextMarkerService.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/TextMarkerService.cs deleted file mode 100644 index 2bb3d8e03..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Errors/TextMarkerService.cs +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Windows; -using System.Windows.Media; -using System.Windows.Threading; -using Tango.Scripting.Editors.Document; -using Tango.Scripting.Editors.Rendering; - -namespace Tango.Scripting.Editors -{ - /// <summary> - /// Handles the text markers for a code editor. - /// </summary> - public sealed class TextMarkerService : DocumentColorizingTransformer, IBackgroundRenderer, ITextMarkerService, ITextViewConnect - { - TextSegmentCollection<TextMarker> markers; - TextDocument document; - - public TextMarkerService(TextDocument document) - { - if (document == null) - throw new ArgumentNullException("document"); - this.document = document; - this.markers = new TextSegmentCollection<TextMarker>(document); - } - - #region ITextMarkerService - public ITextMarker Create(int startOffset, int length) - { - if (markers == null) - throw new InvalidOperationException("Cannot create a marker when not attached to a document"); - - int textLength = document.TextLength; - if (startOffset < 0 || startOffset > textLength) - throw new ArgumentOutOfRangeException("startOffset", startOffset, "Value must be between 0 and " + textLength); - if (length < 0 || startOffset + length > textLength) - throw new ArgumentOutOfRangeException("length", length, "length must not be negative and startOffset+length must not be after the end of the document"); - - TextMarker m = new TextMarker(this, startOffset, length); - markers.Add(m); - // no need to mark segment for redraw: the text marker is invisible until a property is set - return m; - } - - public IEnumerable<ITextMarker> GetMarkersAtOffset(int offset) - { - if (markers == null) - return Enumerable.Empty<ITextMarker>(); - else - return markers.FindSegmentsContaining(offset); - } - - public IEnumerable<ITextMarker> TextMarkers { - get { return markers ?? Enumerable.Empty<ITextMarker>(); } - } - - public void RemoveAll(Predicate<ITextMarker> predicate) - { - if (predicate == null) - throw new ArgumentNullException("predicate"); - if (markers != null) { - foreach (TextMarker m in markers.ToArray()) { - if (predicate(m)) - Remove(m); - } - } - } - - public void Remove(ITextMarker marker) - { - if (marker == null) - throw new ArgumentNullException("marker"); - TextMarker m = marker as TextMarker; - if (markers != null && markers.Remove(m)) { - Redraw(m); - m.OnDeleted(); - } - } - - /// <summary> - /// Redraws the specified text segment. - /// </summary> - internal void Redraw(ISegment segment) - { - foreach (var view in textViews) { - view.Redraw(segment, DispatcherPriority.Normal); - } - if (RedrawRequested != null) - RedrawRequested(this, EventArgs.Empty); - } - - public event EventHandler RedrawRequested; - #endregion - - #region DocumentColorizingTransformer - protected override void ColorizeLine(DocumentLine line) - { - if (markers == null) - return; - int lineStart = line.Offset; - int lineEnd = lineStart + line.Length; - foreach (TextMarker marker in markers.FindOverlappingSegments(lineStart, line.Length)) { - Brush foregroundBrush = null; - if (marker.ForegroundColor != null) { - foregroundBrush = new SolidColorBrush(marker.ForegroundColor.Value); - foregroundBrush.Freeze(); - } - ChangeLinePart( - Math.Max(marker.StartOffset, lineStart), - Math.Min(marker.EndOffset, lineEnd), - element => { - if (foregroundBrush != null) { - element.TextRunProperties.SetForegroundBrush(foregroundBrush); - } - Typeface tf = element.TextRunProperties.Typeface; - element.TextRunProperties.SetTypeface(new Typeface( - tf.FontFamily, - marker.FontStyle ?? tf.Style, - marker.FontWeight ?? tf.Weight, - tf.Stretch - )); - } - ); - } - } - #endregion - - #region IBackgroundRenderer - public KnownLayer Layer { - get { - // draw behind selection - return KnownLayer.Selection; - } - } - - public void Draw(TextView textView, DrawingContext drawingContext) - { - if (textView == null) - throw new ArgumentNullException("textView"); - if (drawingContext == null) - throw new ArgumentNullException("drawingContext"); - if (markers == null || !textView.VisualLinesValid) - return; - var visualLines = textView.VisualLines; - if (visualLines.Count == 0) - return; - int viewStart = visualLines.First().FirstDocumentLine.Offset; - int viewEnd = visualLines.Last().LastDocumentLine.EndOffset; - foreach (TextMarker marker in markers.FindOverlappingSegments(viewStart, viewEnd - viewStart)) { - if (marker.BackgroundColor != null) { - BackgroundGeometryBuilder geoBuilder = new BackgroundGeometryBuilder(); - geoBuilder.AlignToWholePixels = true; - geoBuilder.CornerRadius = 3; - geoBuilder.AddSegment(textView, marker); - Geometry geometry = geoBuilder.CreateGeometry(); - if (geometry != null) { - Color color = marker.BackgroundColor.Value; - SolidColorBrush brush = new SolidColorBrush(color); - brush.Freeze(); - drawingContext.DrawGeometry(brush, null, geometry); - } - } - var underlineMarkerTypes = TextMarkerTypes.SquigglyUnderline | TextMarkerTypes.NormalUnderline | TextMarkerTypes.DottedUnderline; - if ((marker.MarkerTypes & underlineMarkerTypes) != 0) { - foreach (Rect r in BackgroundGeometryBuilder.GetRectsForSegment(textView, marker)) { - Point startPoint = r.BottomLeft; - Point endPoint = r.BottomRight; - - Brush usedBrush = new SolidColorBrush(marker.MarkerColor); - usedBrush.Freeze(); - if ((marker.MarkerTypes & TextMarkerTypes.SquigglyUnderline) != 0) { - double offset = 2.5; - - int count = Math.Max((int)((endPoint.X - startPoint.X) / offset) + 1, 4); - - StreamGeometry geometry = new StreamGeometry(); - - using (StreamGeometryContext ctx = geometry.Open()) { - ctx.BeginFigure(startPoint, false, false); - ctx.PolyLineTo(CreatePoints(startPoint, endPoint, offset, count).ToArray(), true, false); - } - - geometry.Freeze(); - - Pen usedPen = new Pen(usedBrush, 1); - usedPen.Freeze(); - drawingContext.DrawGeometry(Brushes.Transparent, usedPen, geometry); - } - if ((marker.MarkerTypes & TextMarkerTypes.NormalUnderline) != 0) { - Pen usedPen = new Pen(usedBrush, 1); - usedPen.Freeze(); - drawingContext.DrawLine(usedPen, startPoint, endPoint); - } - if ((marker.MarkerTypes & TextMarkerTypes.DottedUnderline) != 0) { - Pen usedPen = new Pen(usedBrush, 1); - usedPen.DashStyle = DashStyles.Dot; - usedPen.Freeze(); - drawingContext.DrawLine(usedPen, startPoint, endPoint); - } - } - } - } - } - - IEnumerable<Point> CreatePoints(Point start, Point end, double offset, int count) - { - for (int i = 0; i < count; i++) - yield return new Point(start.X + i * offset, start.Y - ((i + 1) % 2 == 0 ? offset : 0)); - } - #endregion - - #region ITextViewConnect - readonly List<TextView> textViews = new List<TextView>(); - - void ITextViewConnect.AddToTextView(TextView textView) - { - if (textView != null && !textViews.Contains(textView)) { - Debug.Assert(textView.Document == document); - textViews.Add(textView); - } - } - - void ITextViewConnect.RemoveFromTextView(TextView textView) - { - if (textView != null) { - Debug.Assert(textView.Document == document); - textViews.Remove(textView); - } - } - #endregion - } - - public sealed class TextMarker : TextSegment, ITextMarker - { - readonly TextMarkerService service; - - public TextMarker(TextMarkerService service, int startOffset, int length) - { - if (service == null) - throw new ArgumentNullException("service"); - this.service = service; - this.StartOffset = startOffset; - this.Length = length; - this.markerTypes = TextMarkerTypes.None; - } - - public event EventHandler Deleted; - - public bool IsDeleted { - get { return !this.IsConnectedToCollection; } - } - - public void Delete() - { - service.Remove(this); - } - - internal void OnDeleted() - { - if (Deleted != null) - Deleted(this, EventArgs.Empty); - } - - void Redraw() - { - service.Redraw(this); - } - - Color? backgroundColor; - - public Color? BackgroundColor { - get { return backgroundColor; } - set { - if (backgroundColor != value) { - backgroundColor = value; - Redraw(); - } - } - } - - Color? foregroundColor; - - public Color? ForegroundColor { - get { return foregroundColor; } - set { - if (foregroundColor != value) { - foregroundColor = value; - Redraw(); - } - } - } - - FontWeight? fontWeight; - - public FontWeight? FontWeight { - get { return fontWeight; } - set { - if (fontWeight != value) { - fontWeight = value; - Redraw(); - } - } - } - - FontStyle? fontStyle; - - public FontStyle? FontStyle { - get { return fontStyle; } - set { - if (fontStyle != value) { - fontStyle = value; - Redraw(); - } - } - } - - public object Tag { get; set; } - - TextMarkerTypes markerTypes; - - public TextMarkerTypes MarkerTypes { - get { return markerTypes; } - set { - if (markerTypes != value) { - markerTypes = value; - Redraw(); - } - } - } - - Color markerColor; - - public Color MarkerColor { - get { return markerColor; } - set { - if (markerColor != value) { - markerColor = value; - Redraw(); - } - } - } - - public object ToolTip { get; set; } - } -} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ExtensionMethods.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ExtensionMethods.cs index d112c6141..1605ff281 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ExtensionMethods.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ExtensionMethods.cs @@ -22,7 +22,7 @@ namespace Tango.Scripting.Editors { List<String> args = new List<string>(); - foreach (var lGenericArgument in type.GetGenericArguments()) + foreach (var lGenericArgument in type.GetGenericTypeDefinition().GetGenericArguments()) { args.Add(lGenericArgument.Name); } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs index 72c27f9a9..a05d1fc75 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/OffsetColorizer.cs @@ -30,7 +30,7 @@ namespace Tango.Scripting.Editors.Highlighting { try { - ChangeLinePart(StartOffset, EndOffset, element => element.TextRunProperties.SetBackgroundBrush(Brush)); + ChangeLinePart(StartOffset, EndOffset, element => element.TextRunProperties.SetForegroundBrush(Brush)); } catch { } } 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 1f6139ff6..40f362e08 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" foreground="#3F8FD6" exampleText="this.Do(); base.Do();"/> + <Color name="ThisOrBaseReference" 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;"/> @@ -22,7 +22,7 @@ <Color name="OperatorKeywords" foreground="Pink" exampleText="public static implicit operator..."/> <Color name="ParameterModifiers" foreground="DeepPink" exampleText="(ref int a, params int[] b)"/> <Color name="Modifiers" foreground="#3F8FD6" exampleText="static readonly int a;"/> - <Color name="CustomKeywords" foreground="DarkGray" /> + <Color name="CustomKeywords" foreground="#FAFF00" /> <Color name="Visibility" foreground="#3F8FD6" exampleText="public override void ToString();"/> <Color name="NamespaceKeywords" foreground="#569CD6" exampleText="namespace A.B { using System; }"/> <Color name="GetSetAddRemove" foreground="#3F8FD6" exampleText="int Prop { get; set; }"/> @@ -47,7 +47,26 @@ <!-- This is the main ruleset. --> <RuleSet> - + <Span color="Preprocessor"> + <Begin>\#</Begin> + <RuleSet name="PreprocessorSet"> + <Span> <!-- preprocessor directives that allows comments --> + <Begin > + (define|undef|if|elif|else|endif|line)\b + </Begin> + <RuleSet> + <Span color="Comment" ruleSet="CommentMarkerSet"> + <Begin>//</Begin> + </Span> + </RuleSet> + </Span> + <Span> <!-- preprocessor directives that don't allow comments --> + <Begin > + (region|endregion|error|warning|pragma)\b + </Begin> + </Span> + </RuleSet> + </Span> <!--<Span color="Comment"> <Begin color="XmlDoc/DocComment">///</Begin> @@ -99,7 +118,8 @@ </Rule> <Keywords color="CustomKeywords"> - <Word>#load</Word> + <Word>include</Word> + <Word>import</Word> </Keywords> <Keywords color="ThisOrBaseReference"> @@ -194,7 +214,6 @@ <Word>enum</Word> <Word>float</Word> <Word>int</Word> - <Word>object</Word> <Word>string</Word> <Word>long</Word> <Word>sbyte</Word> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd index 8e02db898..ead5045ab 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/MarkDown-Mode.xshd @@ -5,6 +5,7 @@ <Color name="StrongEmphasis" fontWeight="bold" exampleText="**this** is more important!" /> <Color name="Code" exampleText="this is `int.GetHashCode()`" /> <Color name="BlockQuote" foreground="DarkBlue" exampleText="> This is a\r\n> quote." /> + <Color name="Link" foreground="Blue" exampleText="[text](http://example.com)" /> <Color name="Image" foreground="Green" exampleText="[text][http://example.com/test.png]" /> <Color name="LineBreak" background="LightGray" exampleText="end of line \r\n2nd line " /> @@ -42,6 +43,12 @@ <Rule color="Image"> \!\[.*\]\[.*\] </Rule> + <Rule color="Link"> + \[.*\]\(.*\) + </Rule> + <Rule color="Link"> + \[.*\]\[.*\] + </Rule> <Rule color="LineBreak"> [ ]{2}$ </Rule> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd index 50fdc0e2c..8f0bdef76 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Highlighting/Resources/XML-Mode.xshd @@ -1,13 +1,13 @@ <SyntaxDefinition name="XML" extensions=".xml;.xsl;.xslt;.xsd;.manifest;.config;.addin;.xshd;.wxs;.wxi;.wxl;.proj;.csproj;.vbproj;.ilproj;.booproj;.build;.xfrm;.targets;.xaml;.xpt;.xft;.map;.wsdl;.disco;.ps1xml;.nuspec" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008"> <Color foreground="Green" name="Comment" exampleText="<!-- comment -->" /> - <Color foreground="#3F92D6" name="CData" exampleText="<![CDATA[data]]>" /> - <Color foreground="#C8C8C7" name="DocType" exampleText="<!DOCTYPE rootElement>" /> - <Color foreground="#3F92D6" name="XmlDeclaration" exampleText='<?xml version="1.0"?>' /> - <Color foreground="#3F92D6" name="XmlTag" exampleText='<tag attribute="value" />' /> - <Color foreground="#92CAF4" name="AttributeName" exampleText='<tag attribute="value" />' /> - <Color foreground="#C8C8C7" name="AttributeValue" exampleText='<tag attribute="value" />' /> + <Color foreground="Blue" name="CData" exampleText="<![CDATA[data]]>" /> + <Color foreground="Blue" name="DocType" exampleText="<!DOCTYPE rootElement>" /> + <Color foreground="Blue" name="XmlDeclaration" exampleText='<?xml version="1.0"?>' /> + <Color foreground="DarkMagenta" name="XmlTag" exampleText='<tag attribute="value" />' /> + <Color foreground="Red" name="AttributeName" exampleText='<tag attribute="value" />' /> + <Color foreground="Blue" name="AttributeValue" exampleText='<tag attribute="value" />' /> <Color foreground="Teal" name="Entity" exampleText="index.aspx?a=1&amp;b=2" /> - <Color foreground="Red" name="BrokenEntity" exampleText="index.aspx?a=1&b=2" /> + <Color foreground="Olive" name="BrokenEntity" exampleText="index.aspx?a=1&b=2" /> <RuleSet> <Span color="Comment" multiline="true"> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png Binary files differdeleted file mode 100644 index e8d367028..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/break_point_arrow.png +++ /dev/null diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/event.png b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/event.png Binary files differdeleted file mode 100644 index 4566835c0..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/event.png +++ /dev/null diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/snippet.png b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/snippet.png Binary files differdeleted file mode 100644 index fe4d71eb4..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Images/snippet.png +++ /dev/null diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/CompletionItem.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/CompletionItem.cs index 191f99b6c..c8beebd28 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/CompletionItem.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/CompletionItem.cs @@ -31,7 +31,7 @@ namespace Tango.Scripting.Editors.Intellisense int index = editor.GetCurrentWordStartIndex(); int max = editor.GetCurrentLine().EndOffset; - editor.Document.Replace(index, word.Length, GetCode()); + editor.Document.Replace(index, word.Length,Text); } public abstract BitmapSource Image { get; } @@ -41,11 +41,6 @@ namespace Tango.Scripting.Editors.Intellisense return new BitmapImage(new Uri($"pack://application:,,,/Tango.Scripting.Editors;component/Images/{name}", UriKind.Absolute)); } - protected virtual String GetCode() - { - return Text; - } - public override string ToString() { return Text; diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/EventCompletionItem.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/EventCompletionItem.cs deleted file mode 100644 index 5c510c39f..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/EventCompletionItem.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Media.Imaging; - -namespace Tango.Scripting.Editors.Intellisense -{ - public class EventCompletionItem : CompletionItem - { - private static BitmapSource image = GetImage("event.png"); - - public override string Text => Name; - public override CompletionItemPopupControl PopupControl => new FieldCompletionItemPopup(); - public override BitmapSource Image => image; - - public String Name { get; set; } - public String Class { get; set; } - public String Type { get; set; } - } -} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/HideIntellisenseAttribute.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/HideIntellisenseAttribute.cs deleted file mode 100644 index 548bd909e..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/HideIntellisenseAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -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 8010dc689..28f9ccb9a 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownType.cs @@ -1,14 +1,11 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections; using System.Collections.Generic; -using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; -using System.Windows.Forms; using System.Xml; using Tango.Core; @@ -17,18 +14,16 @@ namespace Tango.Scripting.Editors.Intellisense public class KnownType { private bool _initialized; + private bool _documentationLoaded; - public String Alias { get; set; } - public bool DocumentationLoaded { get; set; } public Type Type { get; private set; } - public String Name { get; set; } + public String Name { get; private set; } public String TypeDefinition { get; private set; } public String FriendlyName { get; private set; } public String Summary { get; set; } public List<KnownTypeConstructor> Constructors { get; set; } public List<KnownTypeMethod> Methods { get; set; } public List<KnownTypeProperty> Properties { get; set; } - public List<KnownTypeEvent> Events { get; set; } public List<KnownTypeMember> Members { get @@ -37,20 +32,12 @@ namespace Tango.Scripting.Editors.Intellisense members.AddRange(Properties); members.AddRange(Methods); - members.AddRange(Events); return members.OrderBy(x => x.Name).ToList(); } } public List<KnownTypeField> Fields { get; set; } - public static List<Assembly> ExtensionMethodsAssemblies { get; set; } - - static KnownType() - { - ExtensionMethodsAssemblies = new List<Assembly>(); - } - public KnownType(Type type) { Summary = "Loading documentation..."; @@ -58,7 +45,6 @@ namespace Tango.Scripting.Editors.Intellisense Methods = new List<KnownTypeMethod>(); Properties = new List<KnownTypeProperty>(); Fields = new List<KnownTypeField>(); - Events = new List<KnownTypeEvent>(); Type = type; Name = type.Name; @@ -132,31 +118,9 @@ namespace Tango.Scripting.Editors.Intellisense { var methods = Type.GetRuntimeMethods().Where(x => x.IsPublic && !x.IsSpecialName).ToList(); - if (Type.IsInterface) - { - foreach (var inter in Type.GetInterfaces()) - { - methods.AddRange(inter.GetRuntimeMethods().Where(x => x.IsPublic && !x.IsSpecialName).ToList()); - } - methods = methods.Distinct().ToList(); - - if (!methods.Exists(x => x.Name == "ToString")) - { - methods.Add(typeof(Object).GetMethod("ToString")); - } - } - //TODO: Separate extension methods! methods.AddRange(Type.GetExtensionMethods(Type.Assembly).ToList()); - if (Type.Namespace.StartsWith("Tango")) - { - foreach (var asm in ExtensionMethodsAssemblies.Where(x => x != Type.Assembly)) - { - methods.AddRange(Type.GetExtensionMethods(asm).ToList()); - } - } - if (typeof(IEnumerable).IsAssignableFrom(Type)) { var linqMethods = typeof(System.Linq.Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).ToList(); @@ -167,13 +131,10 @@ 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; m.ReturnTypeFriendlyName = method.ReturnType.GetFriendlyName(); - m.IsStatic = method.IsStatic && !method.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false); if (method.IsGenericMethod) { @@ -187,11 +148,6 @@ namespace Tango.Scripting.Editors.Intellisense bool isLinq = method.DeclaringType == typeof(Enumerable); - if (isLinq) - { - m.IsStatic = false; - } - for (int j = 0; j < parameters.Count; j++) { var parameter = parameters[j]; @@ -215,14 +171,12 @@ namespace Tango.Scripting.Editors.Intellisense //Load Properties { - var properties = Type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static).ToList(); + var properties = Type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.PropertyType.IsPublic).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; @@ -232,23 +186,6 @@ namespace Tango.Scripting.Editors.Intellisense } } - //Load Events - { - var events = Type.GetRuntimeEvents().ToList(); - - for (int i = 0; i < events.Count; i++) - { - var ev = events[i]; - - if (ev.GetCustomAttribute<HideIntellisenseAttribute>() != null) continue; - - KnownTypeEvent p = new KnownTypeEvent(this); - p.Name = ev.Name; - - Events.Add(p); - } - } - //Load Enum Values { if (Type.IsEnum) @@ -274,9 +211,9 @@ namespace Tango.Scripting.Editors.Intellisense public void LoadDocumentation() { - if (!DocumentationLoaded) + if (!_documentationLoaded) { - DocumentationLoaded = true; + _documentationLoaded = true; Utils.LoadKnownTypeDocs(this); } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeEvent.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeEvent.cs deleted file mode 100644 index 7403d2cbd..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeEvent.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Scripting.Editors.Intellisense -{ - public class KnownTypeEvent : KnownTypeMember - { - public KnownTypeEvent() - { - Summary = "Loading documentation..."; - } - - public KnownTypeEvent(KnownType knownType) : this() - { - Type = knownType; - } - } -} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeMethod.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeMethod.cs index 4cedad377..f84e26fe5 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeMethod.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/KnownTypeMethod.cs @@ -8,8 +8,6 @@ namespace Tango.Scripting.Editors.Intellisense { public class KnownTypeMethod : KnownTypeMember { - public bool IsStatic { get; set; } - public List<KnownTypeMethodParameter> Parameters { get; set; } public List<String> TypeArguments { get; set; } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/SnippetCompletionItem.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/SnippetCompletionItem.cs deleted file mode 100644 index 97807ed19..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/SnippetCompletionItem.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Media.Imaging; - -namespace Tango.Scripting.Editors.Intellisense -{ - public class SnippetCompletionItem : CompletionItem - { - private static BitmapSource image = GetImage("snippet.png"); - - public override string Text => Name; - public override CompletionItemPopupControl PopupControl => new FieldCompletionItemPopup(); - public override BitmapSource Image => image; - - public String Name { get; set; } - public String Code { get; set; } - - protected override string GetCode() - { - return Code; - } - } -} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs index 2ead15d0d..f8cc7072d 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Intellisense/Utils.cs @@ -150,12 +150,7 @@ namespace Tango.Scripting.Editors.Intellisense var property = knownType.Properties[i]; var pDoc = docNodes.FirstOrDefault(x => x.Attributes["name"].InnerText.Contains(knownType.Type.Name + "." + property.Name)); - - if (pDoc != null) - { - var summaryNode = pDoc.SelectSingleNode("summary"); - property.Summary = summaryNode != null ? summaryNode.InnerXml : "No documentation"; - } + property.Summary = pDoc != null ? pDoc.SelectSingleNode("summary").InnerXml : "No documentation"; } } @@ -167,12 +162,7 @@ namespace Tango.Scripting.Editors.Intellisense { var field = knownType.Fields[i]; var pDoc = xmlDoc.SelectSingleNode("//member[starts-with(@name, '" + $"F:{knownType.Type.FullName}.{field.Name}" + "')]"); - - if (pDoc != null) - { - var summaryNode = pDoc.SelectSingleNode("summary"); - field.Summary = summaryNode != null ? summaryNode.InnerXml : "No documentation"; - } + field.Summary = pDoc != null ? pDoc.SelectSingleNode("summary").InnerXml : "No documentation"; } } } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs index 1b1f12ff3..3dabb6b7a 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/TextView.cs @@ -554,7 +554,7 @@ namespace Tango.Scripting.Editors.Rendering /// </summary> public static readonly DependencyProperty LinkTextForegroundBrushProperty = DependencyProperty.Register("LinkTextForegroundBrush", typeof(Brush), typeof(TextView), - new FrameworkPropertyMetadata(Brushes.Gray)); + new FrameworkPropertyMetadata(Brushes.Blue)); /// <summary> /// Gets/sets the Brush used for displaying link texts. diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs index e65ff671d..efa1b087a 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -1,10 +1,8 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.ComponentModel.Design; using System.Diagnostics; using System.IO; using System.Linq; @@ -25,9 +23,7 @@ using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; using System.Xml; -using Tango.Core; using Tango.Core.Commands; -using Tango.Scripting.Core; using Tango.Scripting.Editors.CodeCompletion; using Tango.Scripting.Editors.Document; using Tango.Scripting.Editors.Editing; @@ -37,7 +33,6 @@ using Tango.Scripting.Editors.Highlighting.Xshd; using Tango.Scripting.Editors.Intellisense; using Tango.Scripting.Editors.Popups; using Tango.Scripting.Editors.Rendering; -using Tango.Scripting.Formatting; using Tango.Scripting.Parsing; namespace Tango.Scripting.Editors @@ -47,10 +42,7 @@ 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; @@ -60,48 +52,9 @@ namespace Tango.Scripting.Editors private List<KnownType> _knownTypes; 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; - private static List<CachedAssembly> _cachedAssemblies; - private static List<CachedUsing> _cachedUsings; - private static bool _isLoadingCachedAssemblies; - private static bool _isCacheAssembliesLoaded; - private static bool _isUsingsLoadingStarted; - private static object _loadUsingsLock = new object(); - private static List<SnippetCompletionItem> snippets; - - public static event EventHandler<TangoProgressChangedEventArgs<int>> LoadingSymbolsProgress; - public static event EventHandler LoadingSymbolsStarted; - public static event EventHandler LoadingSymbolsCompleted; - private static event EventHandler KnownTypesAvailable; - public static event EventHandler UsingsLoadingStarted; - public static event EventHandler UsingsLoadingCompleted; #region Mini Classes - private class KnownTypeResult - { - public KnownType KnownType { get; set; } - public bool IsStatic { get; set; } - - public KnownTypeResult() - { - - } - - public KnownTypeResult(KnownType knownType) - { - KnownType = knownType; - } - } - private class ScriptClass { public String Name { get; set; } @@ -132,8 +85,6 @@ namespace Tango.Scripting.Editors #region Properties - public static List<String> BlockedUsingsCache { get; set; } - /// <summary> /// Gets or sets a value indicating whether to enable folding. /// </summary> @@ -159,13 +110,13 @@ namespace Tango.Scripting.Editors /// <summary> /// Gets or sets the reference assemblies. /// </summary> - public ObservableCollection<Assembly> ReferenceAssemblies + public ObservableCollection<ReferenceAssembly> ReferenceAssemblies { - get { return (ObservableCollection<Assembly>)GetValue(ReferenceAssembliesProperty); } + get { return (ObservableCollection<ReferenceAssembly>)GetValue(ReferenceAssembliesProperty); } set { SetValue(ReferenceAssembliesProperty, value); } } public static readonly DependencyProperty ReferenceAssembliesProperty = - DependencyProperty.Register("ReferenceAssemblies", typeof(ObservableCollection<Assembly>), typeof(ScriptEditor), new PropertyMetadata(null, (d, e) => (d as ScriptEditor).OnReferenceAssembliesChanged())); + DependencyProperty.Register("ReferenceAssemblies", typeof(ObservableCollection<ReferenceAssembly>), typeof(ScriptEditor), new PropertyMetadata(null)); public Object CurrentPopupContent { @@ -175,70 +126,6 @@ namespace Tango.Scripting.Editors public static readonly DependencyProperty CurrentPopupContentProperty = DependencyProperty.Register("CurrentPopupContent", typeof(Object), typeof(ScriptEditor), new PropertyMetadata(null)); - public String Code - { - get { return (String)GetValue(CodeProperty); } - set { SetValue(CodeProperty, value); } - } - public static readonly DependencyProperty CodeProperty = - DependencyProperty.Register("Code", typeof(String), typeof(ScriptEditor), new PropertyMetadata(null, (d, e) => (d as ScriptEditor).OnCodeChanged())); - - public ObservableCollection<IScriptSource> AdditionalScripts - { - get { return (ObservableCollection<IScriptSource>)GetValue(AdditionalScriptsProperty); } - set { SetValue(AdditionalScriptsProperty, value); } - } - public static readonly DependencyProperty AdditionalScriptsProperty = - DependencyProperty.Register("AdditionalScripts", typeof(ObservableCollection<IScriptSource>), typeof(ScriptEditor), new PropertyMetadata(null)); - - public Brush ColorizeBrush - { - get { return (Brush)GetValue(ColorizeBrushProperty); } - set { SetValue(ColorizeBrushProperty, value); } - } - public static readonly DependencyProperty ColorizeBrushProperty = - DependencyProperty.Register("ColorizeBrush", typeof(Brush), typeof(ScriptEditor), new PropertyMetadata(new SolidColorBrush(Colors.YellowGreen) { Opacity = 0.5 })); - - 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 @@ -250,87 +137,6 @@ namespace Tango.Scripting.Editors static ScriptEditor() { DefaultStyleKeyProperty.OverrideMetadata(typeof(ScriptEditor), new FrameworkPropertyMetadata(typeof(ScriptEditor))); - - snippets = new List<SnippetCompletionItem>(); - - BlockedUsingsCache = new List<string>(); - - if (KNOWN_TYPES_CACHE_FOLDER == null) - { - KNOWN_TYPES_CACHE_FOLDER = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Scripting", "Cache"); - Directory.CreateDirectory(KNOWN_TYPES_CACHE_FOLDER); - } - - _jsonSettings = new JsonSerializerSettings() - { - TypeNameHandling = TypeNameHandling.Auto, - PreserveReferencesHandling = PreserveReferencesHandling.All - }; - - _knownTypesCache = new Dictionary<Type, KnownType>(); - _cachedAssemblies = new List<CachedAssembly>(); - _cachedUsings = new List<CachedUsing>(); - - snippets.Add(new SnippetCompletionItem() - { - Name = "for", - Code = @"for (int i = 0; i < 10; i++) - { - - }" - }); - - snippets.Add(new SnippetCompletionItem() - { - Name = "while", - Code = @"while (true) - { - - }" - }); - - snippets.Add(new SnippetCompletionItem() - { - Name = "foreach", - Code = @"foreach (var item in items) - { - - }" - }); - - snippets.Add(new SnippetCompletionItem() - { - Name = "prop", - Code = @"public int MyProperty { get; set; }" - }); - - snippets.Add(new SnippetCompletionItem() - { - Name = "do", - Code = @"do - { - - } while (true)" - }); - - snippets.Add(new SnippetCompletionItem() - { - Name = "try", - Code = @"try - { - - } - catch (Exception ex) - { - - }" - }); - - snippets.Add(new SnippetCompletionItem() - { - Name = "cw", - Code = "context.WriteLine(\"\");" - }); } /// <summary> @@ -342,17 +148,16 @@ namespace Tango.Scripting.Editors _current_usings = new List<string>(); - //ReferenceAssemblies = new ObservableCollection<ReferenceAssembly>(); + ReferenceAssemblies = new ObservableCollection<ReferenceAssembly>(); - ////Add basic assemblies... - //ReferenceAssemblies.Add(new ReferenceAssembly(typeof(String))); //mscorelib - //ReferenceAssemblies.Add(new ReferenceAssembly(typeof(Enumerable))); //System.Core + //Add basic assemblies... + ReferenceAssemblies.Add(new ReferenceAssembly(typeof(String))); //mscorelib + ReferenceAssemblies.Add(new ReferenceAssembly(typeof(Enumerable))); //System.Core + ReferenceAssemblies.Add(new ReferenceAssembly(typeof(Tango.Core.CoreSettings))); //System.Core _knownTypes = new List<KnownType>(); _parser = new ScriptParser(); - KnownTypesAvailable += ScriptEditor_KnownTypesAvailable; - TextArea.IndentationStrategy = new Indentation.CSharp.CSharpIndentationStrategy(Options); foldingStrategy = new BraceFoldingStrategy(); @@ -370,59 +175,6 @@ namespace Tango.Scripting.Editors completionWindow.AllowsTransparency = true; completionWindow.ResizeMode = ResizeMode.NoResize; completionWindow.InsertionRequest += CompletionWindow_InsertionRequest; - - TextChanged += ScriptEditor_TextChanged; - - errorMarkerService = new TextMarkerService(Document); - TextArea.TextView.BackgroundRenderers.Add(errorMarkerService); - 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) - { - _update_timer.Stop(); - } - - private void ScriptEditor_KnownTypesAvailable(object sender, EventArgs e) - { - if (sender != this) - { - InvalidateHighlightingPartial(); - } - } - - private bool preventCodeUpdate; - private void ScriptEditor_TextChanged(object sender, EventArgs e) - { - if (!preventCodeUpdate) - { - preventCodeUpdate = true; - Code = Text; - preventCodeUpdate = false; - } - } - - private void OnCodeChanged() - { - if (!preventCodeUpdate) - { - preventCodeUpdate = true; - Text = Code; - preventCodeUpdate = false; - } } #endregion @@ -527,18 +279,18 @@ namespace Tango.Scripting.Editors } else if (e.Key == Key.Oem2) { - //int offset = CaretOffset; - //var line = Document.GetLineByOffset(offset); + int offset = CaretOffset; + var line = Document.GetLineByOffset(offset); - //String text = GetCurrentLineText(); - //if (text.TrimStart('\t', ' ').StartsWith("//")) - //{ - // Document.BeginUpdate(); - // Document.Replace(line, "/// <summary>\n/// \n/// </summary>"); - // Document.EndUpdate(); - // e.Handled = true; - // CaretOffset = Document.GetLineByNumber(line.LineNumber + 1).EndOffset; - //} + String text = GetCurrentLineText(); + if (text.TrimStart('\t', ' ').StartsWith("//")) + { + Document.BeginUpdate(); + Document.Replace(line, "/// <summary>\n/// \n/// </summary>"); + Document.EndUpdate(); + e.Handled = true; + CaretOffset = Document.GetLineByNumber(line.LineNumber + 1).EndOffset; + } } else if (e.Key == Key.End || e.Key == Key.Home) { @@ -552,509 +304,474 @@ namespace Tango.Scripting.Editors private void TextArea_TextEntered(object sender, TextCompositionEventArgs e) { - if (IsReadOnly) return; + List<Object> items = new List<object>(); - try - { - List<Object> items = new List<object>(); + HidePopup(); - HidePopup(); + var lineText = GetCurrentLineText(); + var previousWords = GetPreviousWords(); + var previousWordsLast = previousWords.LastOrDefault(); + String currentWord = previousWordsLast != null ? previousWordsLast.Replace("\t", "") : String.Empty; + String currentWordIncludingParenthesis = currentWord.Split('(').LastOrDefault(); - var lineText = GetCurrentLineText(); - var previousWords = GetPreviousWords(); - var previousWordsLast = previousWords.LastOrDefault(); - String currentWord = previousWordsLast != null ? previousWordsLast.Replace("\t", "") : String.Empty; - String currentWordIncludingParenthesis = currentWord.Split('(').LastOrDefault(); + if (previousWords.Count > 0 && previousWords.First().Trim().StartsWith("//")) return; - if (previousWords.Count > 0 && previousWords.First().Trim().StartsWith("//")) return; + if (e.Text == " " && previousWords.Count > 2 && previousWords[previousWords.Count - 2] == "=") + { + var expression = previousWords.First(); + var knownType = GetKnownTypeFromExpression(expression + "."); - if (e.Text == " " && previousWords.Count > 2 && previousWords[previousWords.Count - 2] == "=") + if (knownType != null && knownType.Type.IsEnum) { - var expression = previousWords.First(); - var knownTypeResult = GetKnownTypeFromExpression(expression + "."); + completionWindow.HideCompletion(); + IList<ICompletionData> data = new List<ICompletionData>(); - if (knownTypeResult != null && knownTypeResult.KnownType.Type.IsEnum) + foreach (var field in knownType.Fields) { - completionWindow.HideCompletion(); - IList<ICompletionData> data = new List<ICompletionData>(); - - foreach (var field in knownTypeResult.KnownType.Fields) + data.Add(new FieldCompletionItem() { - data.Add(new FieldCompletionItem() - { - Class = knownTypeResult.KnownType.FriendlyName, - Name = knownTypeResult.KnownType.FriendlyName + "." + field.Name, - Type = field.ReturnTypeFriendlyName, - Description = field.Summary, - }); - } - - ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); + Class = knownType.FriendlyName, + Name = knownType.FriendlyName + "." + field.Name, + Type = field.ReturnTypeFriendlyName, + Description = field.Summary, + }); } + ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); } - else if (e.Text == " " && GetPreviousWord() == "new") - { - var s = _parser.GetExpressionFirst<FieldDeclarationSyntax>(GetCurrentLineText()); - if (s != null) - { - String type = s.Declaration.Type.ToString(); + } + else if (e.Text == " " && GetPreviousWord() == "new") + { + var s = _parser.GetExpressionFirst<FieldDeclarationSyntax>(GetCurrentLineText()); - IList<ICompletionData> data = new List<ICompletionData>(); + if (s != null) + { + String type = s.Declaration.Type.ToString(); - data.Add(new ClassCompletionItem() - { - Name = type, - Description = "Auto generate assignment...", - }); + IList<ICompletionData> data = new List<ICompletionData>(); - ShowCompletionWindow(data, type); - } - } - else if (e.Text == ";" || e.Text == " ") - { - HideCompletionWindow(); + data.Add(new ClassCompletionItem() + { + Name = type, + Description = "Auto generate assignment...", + }); + + ShowCompletionWindow(data, type); } - else if (e.Text == ".") - { - var knownTypeResult = GetCurrentKnownType(); + } + else if (e.Text == ";" || e.Text == " ") + { + HideCompletionWindow(); + } + else if (e.Text == ".") + { + var knownType = GetCurrentKnownType(); + if (knownType != null) + { + completionWindow.HideCompletion(); IList<ICompletionData> data = new List<ICompletionData>(); - if (knownTypeResult != null) + if (!knownType.Type.IsEnum) { - completionWindow.HideCompletion(); + var typeMembers = knownType.Members.ToList(); - if (!knownTypeResult.KnownType.Type.IsEnum) + foreach (var methodGroup in typeMembers.OfType<KnownTypeMethod>().GroupBy(x => x.NameWithTypeArguments)) { - var typeMembers = knownTypeResult.KnownType.Members.ToList(); + var method = methodGroup.First(); - foreach (var methodGroup in typeMembers.OfType<KnownTypeMethod>().Where(x => (!knownTypeResult.IsStatic && !x.IsStatic) || (knownTypeResult.IsStatic && x.IsStatic)).GroupBy(x => x.NameWithTypeArguments)) + data.Add(new MethodCompletionItem() { - var method = methodGroup.First(); - - data.Add(new MethodCompletionItem() - { - Class = knownTypeResult.KnownType.FriendlyName, - Name = method.NameWithTypeArguments, - ReturnType = method.ReturnTypeFriendlyName, - Description = method.Summary, - Parameters = method.Parameters, - Overloads = methodGroup.Count() - 1, - }); - } + Class = knownType.FriendlyName, + Name = method.NameWithTypeArguments, + ReturnType = method.ReturnTypeFriendlyName, + Description = method.Summary, + Parameters = method.Parameters, + Overloads = methodGroup.Count() - 1, + }); + } - foreach (var ev in typeMembers.OfType<KnownTypeEvent>()) - { - data.Add(new EventCompletionItem() - { - Class = knownTypeResult.KnownType.FriendlyName, - Name = ev.Name, - Description = ev.Summary, - }); - } + foreach (var methodGroup in typeMembers.Where(x => x.GetType() != typeof(KnownTypeMethod)).GroupBy(x => x.Name)) + { + var member = methodGroup.First(); - foreach (var methodGroup in typeMembers.Where(x => x.GetType() != typeof(KnownTypeMethod) && x.GetType() != typeof(KnownTypeEvent)).GroupBy(x => x.Name)) + data.Add(new PropertyCompletionItem() { - var member = methodGroup.First(); + Class = knownType.FriendlyName, + Name = member.Name, + Type = member.ReturnTypeFriendlyName, + Description = member.Summary, + }); - data.Add(new PropertyCompletionItem() - { - Class = knownTypeResult.KnownType.FriendlyName, - Name = member.Name, - Type = member.ReturnTypeFriendlyName, - Description = member.Summary, - }); - } } - else + } + else + { + foreach (var field in knownType.Fields) { - foreach (var field in knownTypeResult.KnownType.Fields) + data.Add(new FieldCompletionItem() { - data.Add(new FieldCompletionItem() - { - Class = knownTypeResult.KnownType.FriendlyName, - Name = field.Name, - Type = field.ReturnTypeFriendlyName, - Description = field.Summary, - }); + Class = knownType.FriendlyName, + Name = field.Name, + Type = field.ReturnTypeFriendlyName, + Description = field.Summary, + }); - } } - - ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); } - else + + ShowCompletionWindow(data.OrderBy(x => x.Text).ToList(), GetCurrentWord()); + } + else + { + var declaredType = GetCurrentDeclaredType(); + + if (declaredType != null) { - var declaredType = GetCurrentDeclaredType(); + completionWindow.HideCompletion(); + IList<ICompletionData> data = new List<ICompletionData>(); - if (declaredType != null) - { - completionWindow.HideCompletion(); + var typeMembers = declaredType.Symbols.ToList(); - var typeMembers = declaredType.Symbols.ToList(); + foreach (var methodGroup in typeMembers.GroupBy(x => x.Name)) + { + var member = methodGroup.First(); - foreach (var methodGroup in typeMembers.GroupBy(x => x.Name)) + if (member.Kind == SymbolKind.Method) { - var member = methodGroup.First(); - - if (member.Kind == SymbolKind.Method) + var methodCompletion = new MethodCompletionItem() { - var methodCompletion = new MethodCompletionItem() - { - Class = declaredType.Name, - Name = member.Name, - ReturnType = member.Type, - Description = member.Summary, - Overloads = methodGroup.Count() - 1, - }; - - - for (int i = 0; i < member.Parameters.Count; i++) - { - var pair = member.Parameters[i]; - - methodCompletion.Parameters.Add(new KnownTypeMethodParameter() - { - Type = pair.Key, - Name = pair.Value, - IsLast = (i == member.Parameters.Count - 1) - }); - } + Class = declaredType.Name, + Name = member.Name, + ReturnType = member.Type, + Description = member.Summary, + Overloads = methodGroup.Count() - 1, + }; - data.Add(methodCompletion); - } - else if (member.Kind == SymbolKind.Property) + for (int i = 0; i < member.Parameters.Count; i++) { - data.Add(new PropertyCompletionItem() + var pair = member.Parameters[i]; + + methodCompletion.Parameters.Add(new KnownTypeMethodParameter() { - Class = declaredType.Name, - Name = member.Name, - Type = member.Type, - Description = member.Summary, + Type = pair.Key, + Name = pair.Value, + IsLast = (i == member.Parameters.Count - 1) }); } - else if (member.Kind == SymbolKind.Field) + + data.Add(methodCompletion); + + } + else if (member.Kind == SymbolKind.Property) + { + data.Add(new PropertyCompletionItem() { - data.Add(new FieldCompletionItem() - { - Class = declaredType.Name, - Name = member.Name, - Type = member.Type, - Description = member.Summary, - }); - } + Class = declaredType.Name, + Name = member.Name, + Type = member.Type, + Description = member.Summary, + }); + } + else if (member.Kind == SymbolKind.Field) + { + data.Add(new FieldCompletionItem() + { + Class = declaredType.Name, + Name = member.Name, + Type = member.Type, + Description = member.Summary, + }); } - - ShowCompletionWindow(data, GetCurrentWord()); } + + ShowCompletionWindow(data, GetCurrentWord()); } } - else if (e.Text == "(" || e.Text == ",") + } + else if (e.Text == "(" || e.Text == ",") + { + completionWindow.HideCompletion(); + + try { - completionWindow.HideCompletion(); + var session = GetConstructionSession(); - try + if (session != null) { - var session = GetConstructionSession(); - - if (session != null) - { - var content = CreateConstructionSessionPopupContent(session); - if (content.Methods.Count > 0) - { - ShowPopup(content); - return; - } - } - - var methodSession = GetMethodSession(); - - if (methodSession != null) + var content = CreateConstructionSessionPopupContent(session); + if (content.Methods.Count > 0) { - var content = CreateMethodSessionPopupContent(methodSession); - if (content.Methods.Count > 0) - { - ShowPopup(content); - return; - } + ShowPopup(content); + return; } + } - var declaredMethodSession = GetDeclaredMethodSession(); + var methodSession = GetMethodSession(); - if (declaredMethodSession != null) + if (methodSession != null) + { + var content = CreateMethodSessionPopupContent(methodSession); + if (content.Methods.Count > 0) { - var content = CreateDeclaredMethodSessionPopupContent(declaredMethodSession); - if (content.Methods.Count > 0) - { - ShowPopup(content); - return; - } + ShowPopup(content); + return; } + } - var staticMethodSession = GetStaticMethodSession(); + var declaredMethodSession = GetDeclaredMethodSession(); - if (staticMethodSession != null) + if (declaredMethodSession != null) + { + var content = CreateDeclaredMethodSessionPopupContent(declaredMethodSession); + if (content.Methods.Count > 0) { - var content = CreateMethodSessionPopupContent(staticMethodSession); - if (content.Methods.Count > 0) - { - ShowPopup(content); - return; - } + ShowPopup(content); + return; } } - catch (Exception ex) - { - Debug.WriteLine(ex); - } } - else if (lineText.StartsWith("using") && e.Text != "\n") + catch (Exception ex) { - if (completionWindow.IsVisible) - { - completionWindow.UpdatePositionFix(); - return; - } + Debug.WriteLine(ex); + } + } + else if (lineText.StartsWith("using")) + { + if (completionWindow.IsVisible) + { + completionWindow.UpdatePositionFix(); + return; + } - IList<ICompletionData> data = new List<ICompletionData>(); + IList<ICompletionData> data = new List<ICompletionData>(); - foreach (var asm in ReferenceAssemblies) + foreach (var asm in ReferenceAssemblies) + { + foreach (var ns in asm.Assembly.GetTypes().Select(x => x.Namespace).Distinct().Where(x => x != null)) { - foreach (var ns in asm.GetTypes().Select(x => x.Namespace).Distinct().Where(x => x != null)) + data.Add(new NamespaceCompletionItem() { - data.Add(new NamespaceCompletionItem() - { - Name = ns, - Assembly = asm.GetName().Name, - }); - } + Name = ns, + Assembly = asm.Assembly.GetName().Name, + }); } + } - data = data.DistinctBy(x => x.Text).ToList(); + data = data.DistinctBy(x => x.Text).ToList(); - ShowCompletionWindow(data, GetCurrentWord()); + ShowCompletionWindow(data, GetCurrentWord()); + } + else if (e.Text == "{") + { + int parentesisCount = lineText.TakeWhile(x => x != '{').Count(x => x == '\"'); + + if (parentesisCount % 2 == 0) + { + Document.Insert(CaretOffset, "}"); + CaretOffset--; } - else if (e.Text == "{") + } + else if (e.Text == "}") + { + if (Document.GetText(CaretOffset - 2, 1) == "{" && Document.GetText(CaretOffset, 1) == "}") { - int parentesisCount = lineText.TakeWhile(x => x != '{').Count(x => x == '\"'); - - if (parentesisCount % 2 == 0) - { - Document.Insert(CaretOffset, "}"); - CaretOffset--; - } + Document.Replace(CaretOffset, 1, ""); } - else if (e.Text == "}") + } + else if (e.Text == "\n") + { + if (Document.GetText(CaretOffset - 3, 1) == "{" && Document.GetText(CaretOffset, 1) == "}") { - if (Document.GetText(CaretOffset - 2, 1) == "{" && Document.GetText(CaretOffset, 1) == "}") - { - Document.Replace(CaretOffset, 1, ""); - } + CaretOffset--; + Document.Insert(CaretOffset, "\n\t"); + } + } + else if (!currentWordIncludingParenthesis.Contains(".") || currentWord[currentWord.Length - 2] == '<') + { + if (completionWindow.IsVisible) + { + completionWindow.UpdatePositionFix(); + return; } - else if (e.Text == "\n") + + var previous_word = GetPreviousWord(); + var word = GetCurrentWord(); + + if (word.Contains("<")) { - if (Document.GetText(CaretOffset - 3, 1) == "{" && Document.GetText(CaretOffset, 1) == "}") - { - CaretOffset--; - Document.Insert(CaretOffset, "\n\t"); - } + word = word.Last(x => x != '<').ToString(); } - else if (!currentWordIncludingParenthesis.Contains(".") || currentWord[currentWord.Length - 2] == '<') + + if (previous_word != word) { - if (completionWindow.IsVisible) + if (_knownTypes.Exists(x => x.Name == previous_word)) { - completionWindow.UpdatePositionFix(); return; } - var previous_word = GetPreviousWord(); - var word = GetCurrentWord(); - - if (word.Contains("<")) + if (_blocking_type_words.Contains(previous_word)) { - word = word.Last(x => x != '<').ToString(); + return; } + } - if (previous_word != word) + if (!String.IsNullOrWhiteSpace(word)) + { + IList<ICompletionData> data = new List<ICompletionData>(); + + foreach (var type in _declaredTypes.Where(x => x.Name.StartsWith(word))) { - if (_knownTypes.Exists(x => x.Name == previous_word)) + if (type.Kind == TypeKind.Struct) { - return; + data.Add(new StructCompletionItem() + { + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); } - - if (_blocking_type_words.Contains(previous_word)) + else if (type.Kind == TypeKind.Enum) { - return; + data.Add(new EnumCompletionItem() + { + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); + } + else if (type.Kind == TypeKind.Interface) + { + data.Add(new InterfaceCompletionItem() + { + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); + } + else if (type.Kind == TypeKind.Class) + { + data.Add(new ClassCompletionItem() + { + Name = type.Name, + Description = type.Summary, + Namespace = type.ContainingNamespace, + Priority = 1, + }); + } + else + { + throw new NotImplementedException("Implement generic item here!"); } } - if (!String.IsNullOrWhiteSpace(word)) + foreach (var type in _knownTypes.ToList().Where(x => x.Name.StartsWith(word))) { - IList<ICompletionData> data = new List<ICompletionData>(); - - foreach (var snippet in snippets) + if (type.Type.IsEnum) { - data.Add(snippet); + data.Add(new EnumCompletionItem() + { + Namespace = type.Type.Namespace, + Description = type.Summary, + Name = type.FriendlyName, + Priority = 0, + }); } - - foreach (var type in _declaredTypes.Where(x => x.Name.StartsWith(word))) + else if (type.Type.IsInterface) { - if (type.Kind == TypeKind.Struct) + data.Add(new InterfaceCompletionItem() { - data.Add(new StructCompletionItem() - { - Name = type.Name, - Description = type.Summary, - Namespace = type.ContainingNamespace, - Priority = 1, - }); - } - else if (type.Kind == TypeKind.Enum) - { - data.Add(new EnumCompletionItem() - { - Name = type.Name, - Description = type.Summary, - Namespace = type.ContainingNamespace, - Priority = 1, - }); - } - else if (type.Kind == TypeKind.Interface) - { - data.Add(new InterfaceCompletionItem() - { - Name = type.Name, - Description = type.Summary, - Namespace = type.ContainingNamespace, - Priority = 1, - }); - } - else if (type.Kind == TypeKind.Class) + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); + } + else if (type.Type.IsValueType) + { + data.Add(new StructCompletionItem() { - data.Add(new ClassCompletionItem() - { - Name = type.Name, - Description = type.Summary, - Namespace = type.ContainingNamespace, - Priority = 1, - }); - } - else + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); + } + else if (type.Type.IsClass) + { + data.Add(new ClassCompletionItem() { - throw new NotImplementedException("Implement generic item here!"); - } + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); + } + else + { + throw new NotImplementedException("Implement generic item here."); } + } - foreach (var type in _knownTypes.ToList().Where(x => x.Name.StartsWith(word))) + foreach (var symbol in _parser.GetContextSymbols(Document.Text, CaretOffset).Where(x => x.Name.StartsWith(GetCurrentWord()))) + { + if (symbol.Kind == SymbolKind.Property) { - if (type.Type.IsEnum) - { - data.Add(new EnumCompletionItem() - { - Namespace = type.Type.Namespace, - Description = type.Summary, - Name = type.FriendlyName, - Priority = 0, - }); - } - else if (type.Type.IsInterface) + data.Add(new PropertyCompletionItem() { - data.Add(new InterfaceCompletionItem() - { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - Priority = 0, - }); - } - else if (type.Type.IsValueType) - { - data.Add(new StructCompletionItem() - { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - Priority = 0, - }); - } - else if (type.Type.IsClass) - { - data.Add(new ClassCompletionItem() - { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - Priority = 0, - }); - } - else + Class = symbol.Class, + Description = symbol.Summary, + Name = symbol.Name, + Type = symbol.Type, + Priority = 2, + }); + } + else if (symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Local || symbol.Kind == SymbolKind.Parameter) + { + data.Add(new FieldCompletionItem() { - throw new NotImplementedException("Implement generic item here."); - } + Class = symbol.Class, + Description = symbol.Summary, + Name = symbol.Name, + Type = symbol.Type, + Priority = 2, + }); } - - foreach (var symbol in _parser.GetContextSymbols(Document.Text, CaretOffset).Where(x => x.Name.StartsWith(GetCurrentWord()))) + else if (symbol.Kind == SymbolKind.Method) { - if (symbol.Kind == SymbolKind.Property) + var methodCompletion = new MethodCompletionItem() { - data.Add(new PropertyCompletionItem() - { - Class = symbol.Class, - Description = symbol.Summary, - Name = symbol.Name, - Type = symbol.Type, - Priority = 2, - }); - } - else if (symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Local || symbol.Kind == SymbolKind.Parameter) + Class = symbol.Class, + Description = symbol.Summary, + Name = symbol.Name, + ReturnType = symbol.Type, + Priority = 2, + }; + + for (int i = 0; i < symbol.Parameters.Count; i++) { - data.Add(new FieldCompletionItem() + var pair = symbol.Parameters[i]; + + methodCompletion.Parameters.Add(new KnownTypeMethodParameter() { - Class = symbol.Class, - Description = symbol.Summary, - Name = symbol.Name, - Type = symbol.Type, - Priority = 2, + Type = pair.Key, + Name = pair.Value, + IsLast = (i == symbol.Parameters.Count - 1) }); } - else if (symbol.Kind == SymbolKind.Method) - { - var methodCompletion = new MethodCompletionItem() - { - Class = symbol.Class, - Description = symbol.Summary, - Name = symbol.Name, - ReturnType = symbol.Type, - Priority = 2, - }; - - for (int i = 0; i < symbol.Parameters.Count; i++) - { - var pair = symbol.Parameters[i]; - methodCompletion.Parameters.Add(new KnownTypeMethodParameter() - { - Type = pair.Key, - Name = pair.Value, - IsLast = (i == symbol.Parameters.Count - 1) - }); - } - - data.Add(methodCompletion); - } + data.Add(methodCompletion); } - - ShowCompletionWindow(data, word); } + + ShowCompletionWindow(data, word); } } - catch (Exception ex) - { - Debug.WriteLine(ex.ToString()); - } } #endregion @@ -1075,7 +792,7 @@ namespace Tango.Scripting.Editors IList<ICompletionData> data = completionWindow.CompletionList.CompletionData; data.Clear(); - foreach (var item in suggestions.DistinctBy(x => x.Text)) + foreach (var item in suggestions) { data.Add(item); } @@ -1147,23 +864,16 @@ namespace Tango.Scripting.Editors return list; } - private KnownTypeResult GetCurrentKnownType() + private KnownType GetCurrentKnownType() { var expression = GetPreviousWords().LastOrDefault(); return GetKnownTypeFromExpression(expression); } - private KnownTypeResult GetKnownTypeFromExpression(String expression) + private KnownType GetKnownTypeFromExpression(String expression) { if (expression != null) { - var insideMethodExp = expression.Split('(').LastOrDefault(); - - if (insideMethodExp != null) - { - expression = insideMethodExp; - } - var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList(); var variableName = tree.FirstOrDefault(); @@ -1174,7 +884,7 @@ namespace Tango.Scripting.Editors if (enumType != null) { - return new KnownTypeResult(enumType); + return enumType; } tree.RemoveAt(0); @@ -1183,8 +893,7 @@ namespace Tango.Scripting.Editors if (variable != null) { - var name = Regex.Replace(variable.Type, "<.+>", "<T>"); - var knownType = _knownTypes.FirstOrDefault(x => name == x.FriendlyName || name == x.Alias); + var knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == Regex.Replace(variable.Type, "<.+>", "<T>")); if (knownType != null) { @@ -1202,37 +911,9 @@ namespace Tango.Scripting.Editors knownType = _knownTypes.FirstOrDefault(x => x.Type.Namespace + "." + x.Type.Name == member.ReturnType.Namespace + "." + member.ReturnType.Name); } - return new KnownTypeResult(knownType); - } - else //Maybe a variable of a declared type... - { - if (tree.Count > 0) - { - var memberName = tree[0]; - var declaredType = _declaredTypes.SingleOrDefault(x => x.Name == name); - - if (declaredType != null) - { - var member = declaredType.Symbols.FirstOrDefault(x => x.Name == memberName); - if (member != null) - { - knownType = _knownTypes.SingleOrDefault(x => x.Name.ToLower() == member.Type.ToLower()); - - if (knownType != null) - { - return new KnownTypeResult(knownType); - } - } - } - } + return knownType; } } - else - { - //Maybe static... - var type = _knownTypes.FirstOrDefault(x => x.Name == variableName || x.Alias == variableName); - return type != null ? new KnownTypeResult(type) { IsStatic = true } : null; - } } } @@ -1245,13 +926,6 @@ namespace Tango.Scripting.Editors if (expression != null) { - var insideMethodExp = expression.Split('(').LastOrDefault(); - - if (insideMethodExp != null) - { - expression = insideMethodExp; - } - var tree = expression.Split('.').Select(x => x.Remove(@"\n|\t|\r|\(.*\)|\[.*\]|\s")).ToList(); var variableName = tree.FirstOrDefault(); @@ -1284,11 +958,6 @@ namespace Tango.Scripting.Editors return declaredType; } } - else - { - //Maybe static... - return _declaredTypes.FirstOrDefault(x => x.Name == variableName); - } } } @@ -1378,7 +1047,7 @@ namespace Tango.Scripting.Editors foreach (var m in session.Type.Methods.Where(x => x.Name == session.MethodName)) { MethodDescription method = new MethodDescription(); - method.ReturnType = m.ReturnTypeFriendlyName; + method.ReturnType = session.Type.Name; method.Description = m.Summary; method.Name = m.NameWithTypeArguments; method.Class = session.Type.FriendlyName; @@ -1471,364 +1140,33 @@ namespace Tango.Scripting.Editors return popup; } - public void LoadUsingsSymbols(List<Assembly> assemblies, List<String> usings) - { - lock (_loadUsingsLock) - { - LoadingSymbolsStarted?.Invoke(null, new EventArgs()); - - var allTypes = assemblies.SelectMany(x => x.GetTypes()); - - foreach (var use in usings) - { - if (!_cachedUsings.Exists(x => x.Namespace == use)) - { - if (!_isUsingsLoadingStarted) - { - _isUsingsLoadingStarted = true; - UsingsLoadingStarted?.Invoke(this, new EventArgs()); - } - - var useFileName = System.IO.Path.Combine(KNOWN_TYPES_CACHE_FOLDER, use + ".json"); - - if (File.Exists(useFileName)) - { - LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() - { - Progress = new TangoProgress<int>() - { - IsIndeterminate = true, - Maximum = 100, - Message = $"Loading symbols for '{use}'..." - } - }); - - CachedUsing cached = JsonConvert.DeserializeObject<CachedUsing>(File.ReadAllText(useFileName), _jsonSettings); - _cachedUsings.Add(cached); - foreach (var knownType in cached.KnownTypes) - { - _knownTypesCache.Add(knownType.Type, knownType); - } - - KnownTypesAvailable?.Invoke(this, new EventArgs()); - InvalidateHighlightingPartial(); - - continue; - } - - var useTypes = allTypes.Where(x => x.IsVisible && x.IsPublic && x.Namespace == use).ToList(); - - CachedUsing cachedUsing = new CachedUsing(); - cachedUsing.Namespace = use; - _cachedUsings.Add(cachedUsing); - - int i = 1; - - foreach (var type in useTypes) - { - LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() - { - Progress = new TangoProgress<int>() - { - IsIndeterminate = false, - Maximum = useTypes.Count, - Value = i++, - Message = $"Loading symbols for '{use}'..." - } - }); - - KnownType knownType = new KnownType(type); - - if (type.IsPrimitive) - { - if (type == typeof(Int32)) - { - knownType.Alias = "int"; - } - else if (type == typeof(float)) - { - knownType.Alias = "float"; - } - else if (type == typeof(Double)) - { - knownType.Alias = "double"; - } - else if (type == typeof(long)) - { - knownType.Alias = "long"; - } - else if (type == typeof(bool)) - { - knownType.Alias = "bool"; - } - else if (type == typeof(uint)) - { - knownType.Alias = "uint"; - } - } - else if (type == typeof(String)) - { - knownType.Alias = "string"; - } - - _knownTypesCache.Add(type, knownType); - cachedUsing.KnownTypes.Add(knownType); - knownType.LoadDocumentation(); - } - - if (!BlockedUsingsCache.Exists(x => use.StartsWith(x))) - { - Task.Factory.StartNew(() => - { - var json = JsonConvert.SerializeObject(cachedUsing, _jsonSettings); - File.WriteAllText(useFileName, json); - }); - } - } - } - - if (_isUsingsLoadingStarted) - { - UsingsLoadingCompleted?.Invoke(this, new EventArgs()); - } - - LoadingSymbolsCompleted?.Invoke(null, new EventArgs()); - } - } - - //public static void LoadCachedAssemblies(List<Assembly> assemblies, List<String> usings = null) - //{ - // if (_isLoadingCachedAssemblies) return; - - // _isLoadingCachedAssemblies = true; - - // LoadingSymbolsStarted?.Invoke(null, new EventArgs()); - - // if (!_isCacheAssembliesLoaded) - // { - // foreach (var file in System.IO.Directory.GetFiles(KNOWN_TYPES_CACHE_FOLDER)) - // { - // try - // { - // LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() - // { - // Progress = new TangoProgress<int>() - // { - // IsIndeterminate = true, - // Maximum = 100, - // Message = $"Loading metadata cache for '{System.IO.Path.GetFileName(file)}'..." - // } - // }); - - // var cachedAssembly = JsonConvert.DeserializeObject<CachedAssembly>(System.IO.File.ReadAllText(file), _jsonSettings); - - // foreach (var knownType in cachedAssembly.KnownTypes) - // { - // _knownTypesCache.Add(knownType.Type, knownType); - // } - - // _cachedAssemblies.Add(cachedAssembly); - // } - // catch { } - // } - - // _isCacheAssembliesLoaded = true; - // } - - // foreach (var asm in assemblies) - // { - // if (!_cachedAssemblies.Exists(x => x.Name == asm.FullName)) - // { - // String asmFileName = System.IO.Path.GetFileName(asm.Location); - - // CachedAssembly cachedAssembly = new CachedAssembly(); - // cachedAssembly.Name = asm.FullName; - // _cachedAssemblies.Add(cachedAssembly); - - // var types = asm.GetTypes().Where(x => x.IsVisible && x.IsPublic).ToList(); - - // int i = 0; - - // foreach (var type in types) - // { - // LoadingSymbolsProgress?.Invoke(null, new TangoProgressChangedEventArgs<int>() - // { - // Progress = new TangoProgress<int>() - // { - // IsIndeterminate = false, - // Maximum = types.Count, - // Value = i++, - // Message = $"Caching metadata for '{asmFileName}'..." - // } - // }); - - // KnownType knownType = new KnownType(type); - - // if (type.IsPrimitive) - // { - // if (type == typeof(Int32)) - // { - // knownType.Alias = "int"; - // } - // else if (type == typeof(float)) - // { - // knownType.Alias = "float"; - // } - // else if (type == typeof(Double)) - // { - // knownType.Alias = "double"; - // } - // else if (type == typeof(long)) - // { - // knownType.Alias = "long"; - // } - // else if (type == typeof(bool)) - // { - // knownType.Alias = "bool"; - // } - // else if (type == typeof(uint)) - // { - // knownType.Alias = "uint"; - // } - // } - - // _knownTypesCache.Add(type, knownType); - // cachedAssembly.KnownTypes.Add(knownType); - // //knownType.LoadDocumentation(); - // } - - // String cachedAssemblyFile = System.IO.Path.Combine(KNOWN_TYPES_CACHE_FOLDER, asmFileName); - // File.WriteAllText(cachedAssemblyFile, JsonConvert.SerializeObject(cachedAssembly, _jsonSettings)); - // } - // } - - // LoadingSymbolsCompleted?.Invoke(null, new EventArgs()); - - // _isLoadingCachedAssemblies = false; - //} - - private void InvalidateHighlightingPartial() - { - List<Assembly> assemblies = new List<Assembly>(); - Dispatcher.Invoke(() => - { - assemblies = ReferenceAssemblies.ToList(); - }); - - var usings = _current_usings.ToList(); - - _knownTypes.Clear(); - - foreach (var knownType in _knownTypesCache.ToList().Select(x => x.Value).ToList()) - { - if (usings.Exists(x => knownType.Type.Namespace == x) && assemblies.Exists(x => x == knownType.Type.Assembly)) - { - lock (_knownTypes) - { - _knownTypes.Add(knownType); - } - } - } - - if (_knownTypes.Count > 0 || _declaredTypes.Count > 0) - { - String text = String.Empty; - - Stream xshd_stream = typeof(ScriptEditor).Assembly.GetManifestResourceStream("Tango.Scripting.Editors.Highlighting.Resources.CSharp-Mode.xshd"); - - using (StreamReader reader = new StreamReader(xshd_stream)) - { - text = reader.ReadToEnd(); - } - - List<String> referenceTypes = new List<string>(); - List<String> interfaceTypes = new List<string>(); - - lock (_knownTypes) - { - foreach (var type in _knownTypes.ToList().Where(x => x != null)) - { - String name = type.Name; - - if (type.Type.ContainsGenericParameters) - { - name = new String(name.TakeWhile(x => x != '`').ToArray()); - } - - if (type.Type.IsInterface || type.Type.IsEnum) - { - interfaceTypes.Add(String.Format("<Word>{0}</Word>", name)); - } - else if (type.Type.IsClass || (type.Type.IsValueType)) - { - referenceTypes.Add(String.Format("<Word>{0}</Word>", name)); - } - } - } - - foreach (var type in _declaredTypes) - { - if (type.Kind == TypeKind.Interface || type.Kind == TypeKind.Enum) - { - interfaceTypes.Add(String.Format("<Word>{0}</Word>", type.Name)); - } - else if (type.Kind == TypeKind.Class) - { - referenceTypes.Add(String.Format("<Word>{0}</Word>", type.Name)); - } - } - - if (referenceTypes.Count > 0) - { - text = text.Replace("<Word>@ReferenceTypes@</Word>", String.Join(Environment.NewLine, referenceTypes.Distinct())); - } - - if (interfaceTypes.Count > 0) - { - text = text.Replace("<Word>@InterfaceTypes@</Word>", String.Join(Environment.NewLine, interfaceTypes.Distinct())); - } - - MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(text)); - - XmlTextReader xshd_reader = new XmlTextReader(ms); - - Dispatcher.Invoke(new Action(() => - { - SyntaxHighlighting = HighlightingLoader.Load(xshd_reader, HighlightingManager.Instance); - xshd_reader.Close(); - ms.Dispose(); - })); - } - } - - public void InvalidateHighlighting(bool loadKnownTypes = true) + private void InvalidateHighlighting() { if (!_isLoadingTypes) { _isLoadingTypes = true; + _knownTypes.Clear(); var assemblies = ReferenceAssemblies.ToList(); - KnownType.ExtensionMethodsAssemblies = assemblies.ToList(); var usings = _current_usings.ToList(); Thread t = new Thread(() => { - LoadUsingsSymbols(assemblies, usings); - - if (loadKnownTypes) + foreach (var asm in assemblies.Select(x => x.Assembly)) { - _knownTypes.Clear(); - - foreach (var knownType in _knownTypesCache.ToList().Select(x => x.Value).ToList()) + Parallel.ForEach(asm.GetTypes().Where(x => x.IsVisible && x.IsPublic && !x.IsPrimitive), (type) => { - if (usings.Exists(x => knownType.Type.Namespace == x) && assemblies.Exists(x => x == knownType.Type.Assembly)) + if (usings.Exists(x => type.Namespace == x)) { lock (_knownTypes) { - _knownTypes.Add(knownType); + if (!_knownTypes.Exists(x => x.Type.FullName == type.FullName)) + { + _knownTypes.Add(new KnownType(type)); + } } } - } + }); } if (_knownTypes.Count > 0 || _declaredTypes.Count > 0) @@ -1901,10 +1239,10 @@ namespace Tango.Scripting.Editors })); - //foreach (var knownType in _knownTypes) - //{ - // knownType.LoadDocumentation(); - //} + foreach (var knownType in _knownTypes) + { + knownType.LoadDocumentation(); + } } _isLoadingTypes = false; @@ -1918,19 +1256,10 @@ namespace Tango.Scripting.Editors { var declaredTypes = _parser.GetDeclaredTypes(Text); - if (AdditionalScripts != null) - { - foreach (var script in AdditionalScripts) - { - declaredTypes.AddRange(_parser.GetDeclaredTypes(script.Code)); - } - } - - if (declaredTypes.Exists(x => !_declaredTypes.Exists(y => y.Name == x.Name)) || _declaredTypes.Exists(x => !declaredTypes.Exists(y => y.Name == x.Name))) { _declaredTypes = declaredTypes; - InvalidateHighlighting(false); + InvalidateHighlighting(); } _declaredTypes = declaredTypes; @@ -1982,8 +1311,7 @@ namespace Tango.Scripting.Editors private void IndentCode() { - Text = CodeFormatter.Format(Text); - //Text = Indentation.CSharp.CSharpIndentationHelper.IndentCSharpCode(Text); + Text = Indentation.CSharp.CSharpIndentationHelper.IndentCSharpCode(Text); //Text = _parser.IndentCSharpCode(Text); } @@ -2061,11 +1389,7 @@ namespace Tango.Scripting.Editors private ConstructionSession GetConstructionSession() { - var currentLine = GetCurrentLineText(); - - //if (currentLine.Count(x => x == '(') > 1) return null; - - var expression = _parser.GetCurrentConstructionExpression(currentLine); + var expression = _parser.GetCurrentConstructionExpression(GetCurrentLineText()); if (expression != null) { @@ -2121,64 +1445,13 @@ namespace Tango.Scripting.Editors } } - else - { - var expression2 = _parser.GetCurrentConstructionExpressionAlt(GetCurrentLineText()); - - if (expression2 != null && expression2.Identifier != null) - { - ConstructionSession session = new ConstructionSession(); - - var line = GetCurrentLine(); - int parameterIndex = 0; - for (int i = CaretOffset; i > line.Offset; i--) - { - String c = Document.GetText(i, 1); - - if (c == "(") - { - KnownType type = null; - - if (expression2.Identifier != null) - { - var typeName = expression2.Identifier.ToString(); - type = _knownTypes.FirstOrDefault(x => x.Type.Name == typeName); - - if (type != null) - { - session.Type = type; - session.ParameterIndex = parameterIndex; - return session; - } - else - { - return null; - } - } - } - else if (c == ",") - { - parameterIndex++; - } - } - } - } return null; } private MethodSession GetMethodSession() { - var currentLine = GetCurrentLineText(); - - if (currentLine.Count(x => x == '(') > 1) - { - currentLine = currentLine.Split('(')[currentLine.Split('(').Length - 2]; - } - - currentLine = Regex.Replace(currentLine, "(?<=\")(.*?)(?=\")", string.Empty); - - var words = currentLine.Split(' '); + var words = GetCurrentLineText().Split(' '); if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void")) { @@ -2190,8 +1463,6 @@ namespace Tango.Scripting.Editors if (expression != null) { int parameterIndex = expression.Count(x => x == ','); - - expression = new string(expression.TakeWhile(x => x != '(').ToArray()); var tree = expression.Split('.').Select(x => x.Remove(@"\n|\r|\s|\t|\(|\)|\[|\]|<.*>")).ToList(); @@ -2237,82 +1508,16 @@ namespace Tango.Scripting.Editors return null; } - private MethodSession GetStaticMethodSession() - { - var words = GetCurrentLineText().Split(' '); - - if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void")) - { - return null; - } - - var expression = words.LastOrDefault(); - - if (expression != null) - { - int parameterIndex = expression.Count(x => x == ','); - expression = new string(expression.TakeWhile(x => x != '(').ToArray()); - - var tree = expression.Split('.').Select(x => x.Remove(@"\n|\r|\s|\t|\(|\)|\[|\]|<.*>")).ToList(); - var variableName = tree.FirstOrDefault(); - - if (variableName != null && tree.Count > 1) - { - tree.RemoveAt(0); - var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); - var variable = variableName; - - if (variable != null) - { - var knownType = _knownTypes.FirstOrDefault(x => x.FriendlyName == Regex.Replace(variable, "<.+>", "<T>")); - - if (knownType != null) - { - while (tree.Count > 1) - { - var memberName = tree.First(); - tree.RemoveAt(0); - var member = knownType.Members.FirstOrDefault(x => x.Name == memberName); - - if (member == null) - { - return null; - } - - knownType = _knownTypes.FirstOrDefault(x => x.Type.Namespace + "." + x.Type.Name == member.ReturnType.Namespace + "." + member.ReturnType.Name); - } - - return new MethodSession() - { - Type = knownType, - MethodName = tree.Last(), - ParameterIndex = parameterIndex, - }; - } - } - } - } - - return null; - } - private DeclaredMethodSession GetDeclaredMethodSession() { - var currentLine = GetCurrentLineText(); - - if (currentLine.Count(x => x == '(') > 1) - { - currentLine = currentLine.Split('(')[currentLine.Split('(').Length - 2]; - } - - var words = currentLine.Split(' '); + var words = GetCurrentLineText().Split(' '); if (words.Count() > 0 && (words.First() == "private" || words.First() == "public" || words.First() == "void")) { return null; } - var expression = currentLine; + var expression = GetPreviousWords().LastOrDefault(); if (expression != null) { @@ -2327,7 +1532,7 @@ namespace Tango.Scripting.Editors if (variable != null) { - var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Type, "<.+>", "<T>")); + var declaredType = _declaredTypes.FirstOrDefault(x => x.Name == Regex.Replace(variable.Class, "<.+>", "<T>")); if (declaredType != null) { @@ -2386,413 +1591,5 @@ namespace Tango.Scripting.Editors } #endregion - - #region Reference Assemblies Changed - - private void OnReferenceAssembliesChanged() - { - if (ReferenceAssemblies != null) - { - ReferenceAssemblies.CollectionChanged -= ReferenceAssemblies_CollectionChanged; - ReferenceAssemblies.CollectionChanged += ReferenceAssemblies_CollectionChanged; - - InvalidateHighlighting(); - } - } - - private void ReferenceAssemblies_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - InvalidateHighlighting(); - } - - #endregion - - #region Public Methods - - public void FormatCode() - { - try - { - int index = CaretOffset; - Document.BeginUpdate(); - IndentCode(); - Document.EndUpdate(); - CaretOffset = index; - } - catch - { - Debug.WriteLine("Error formatting code."); - } - } - - public void Highlight(int position, int length, int line) - { - Select(position, Math.Max(length, 1)); - ScrollToLine(line); - } - - public void InsertCode(String code) - { - Document.Insert(TextArea.Caret.Offset, code); - } - - public int Find(String text) - { - if (String.IsNullOrEmpty(text)) return -1; - - string txt = Document.Text; - int index = txt.IndexOf(text, TextArea.Caret.Offset); - - if (index > -1) - { - Select(index, text.Length); - ScrollToLine(TextArea.Selection.StartPosition.Line); - } - else - { - index = txt.IndexOf(text, 0); - - if (index > -1) - { - Select(index, text.Length); - ScrollToLine(TextArea.Selection.StartPosition.Line); - } - else - { - Select(0, 0); - System.Media.SystemSounds.Beep.Play(); - } - } - - return index; - } - - public int ReplaceNext(String text, String replace) - { - if (String.IsNullOrEmpty(text)) return -1; - - String selectedText = TextArea.Selection.GetText(); - - if (selectedText == text) - { - TextArea.Selection.ReplaceSelectionWithText(replace); - } - - return Find(text); - } - - public int ReplaceAll(String text, String replace) - { - int counter = 0; - - Select(0, 0); - - while (ReplaceNext(text, replace) > -1) - { - counter++; - }; - - return counter; - } - - public void ColorizeByKeyword(String text) - { - ResetColorizationByKeyword(); - - if (String.IsNullOrEmpty(text)) return; - - var txt = Document.Text; - - var indexes = txt.AllIndexesOf(text).ToList(); - - foreach (var index in indexes) - { - Document.BeginUpdate(); - - var line = Document.GetLineByOffset(index); - - OffsetColorizer colorizer = new OffsetColorizer(line, index, index + text.Length, ColorizeBrush); - TextArea.TextView.LineTransformers.Add(colorizer); - - Document.EndUpdate(); - } - } - - public void ResetColorizationByKeyword() - { - Document.BeginUpdate(); - - for (int i = 0; i < TextArea.TextView.LineTransformers.Count; i++) - { - if (TextArea.TextView.LineTransformers[i] is OffsetColorizer) - { - TextArea.TextView.LineTransformers.RemoveAt(i); - i--; - } - } - - Document.EndUpdate(); - } - - public void HighlighError(int position, int length) - { - try - { - ITextMarker marker = errorMarkerService.Create(position, length); - marker.MarkerTypes = TextMarkerTypes.SquigglyUnderline; - marker.MarkerColor = Colors.Red; - } - catch (Exception ex) - { - Debug.WriteLine($"Error highlighting script error.\n{ex.ToString()}"); - } - } - - public void ClearErrors() - { - 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 11e023f86..ce7c361e3 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 @@ -77,9 +77,6 @@ <Reference Include="Microsoft.CodeAnalysis.CSharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <HintPath>..\..\packages\Microsoft.CodeAnalysis.CSharp.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll</HintPath> </Reference> - <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> - <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> - </Reference> <Reference Include="PresentationCore"> <RequiredTargetFramework>3.0</RequiredTargetFramework> </Reference> @@ -180,9 +177,6 @@ <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" /> <Compile Include="CodeCompletion\CompletionListBoxItem.cs" /> <Compile Include="CodeCompletion\CompletionWindowBase.cs" /> @@ -197,19 +191,14 @@ <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" /> <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\HideIntellisenseAttribute.cs" /> <Compile Include="Intellisense\ICompletionItem.cs" /> <Compile Include="Intellisense\ICompletionProvider.cs" /> <Compile Include="Intellisense\InterfaceCompletionItem.cs" /> @@ -347,7 +336,6 @@ <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" /> @@ -360,7 +348,6 @@ <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" /> @@ -513,7 +500,6 @@ <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" /> @@ -593,14 +579,6 @@ <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> @@ -648,18 +626,9 @@ <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> - <Resource Include="Images\event.png" /> - </ItemGroup> - <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" /> + <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> </Project>
\ No newline at end of file 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 deleted file mode 100644 index 70a4840c4..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors_di35u2uj_wpftmp.csproj +++ /dev/null @@ -1,628 +0,0 @@ -<?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 cd9977520..d2fc9e02b 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/TextEditor.cs @@ -3,7 +3,6 @@ using System; using System.ComponentModel; -using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -25,1229 +24,1121 @@ 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) - { - 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); - } - } - } - } - } + /// <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); + } + } + } + } + } }
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml index 5de763df3..ce5cb39e1 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Themes/Generic.xaml @@ -47,19 +47,12 @@ <BitmapImage x:Key="namespace" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/namespace.png" /> <BitmapImage x:Key="method" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/method.png" /> <BitmapImage x:Key="property" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/property.png" /> - <BitmapImage x:Key="event" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/event.png" /> - <BitmapImage x:Key="snippet" UriSource="pack://application:,,,/Tango.Scripting.Editors;component/Images/snippet.png" /> <!--Converters--> <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> <converters:BooleanToVisibilityInversedConverter x:Key="BooleanToVisibilityInversedConverter" /> <Style TargetType="{x:Type completion:CompletionList}"> - <Style.Resources> - <Style TargetType="ToolTip"> - - </Style> - </Style.Resources> <Setter Property="Background" Value="{StaticResource CompletionBackgroundBrush}"></Setter> <Setter Property="BorderThickness" Value="0"></Setter> @@ -90,6 +83,95 @@ <Setter.Value> <DataTemplate> <Border Background="{StaticResource CompletionToolTipBackgroundBrush}" CornerRadius="3" BorderThickness="0.5" BorderBrush="#434343" Padding="10 5" TextElement.Foreground="{StaticResource ScriptForegroundBrush}" TextElement.FontSize="12"> + <!--<ContentControl Content="{Binding}"> + <ContentControl.Style> + <Style TargetType="ContentControl"> + <Setter Property="ContentTemplate"> + <Setter.Value> + <DataTemplate> + <ContentPresenter Content="{Binding PopupControl}" /> + </DataTemplate> + </Setter.Value> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding Type}" Value="method"> + <Setter Property="ContentTemplate"> + <Setter.Value> + <DataTemplate> + <StackPanel> + <StackPanel Orientation="Horizontal"> + <TextBlock Text="{Binding ReturnType}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> + <TextBlock Margin="5 0 0 0" Text="{Binding Class}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> + <TextBlock>.</TextBlock> + <TextBlock Text="{Binding Text}"></TextBlock> + <TextBlock>(</TextBlock> + <ItemsControl ItemsSource="{Binding Parameters}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <StackPanel Orientation="Horizontal"></StackPanel> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemTemplate> + <DataTemplate> + <StackPanel Orientation="Horizontal"> + <TextBlock Text="{Binding Type.Name}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> + <TextBlock Margin="5 0 0 0" Text="{Binding Name}"></TextBlock> + <TextBlock Margin="0 0 5 0" Text="," Visibility="{Binding IsLast,Converter={StaticResource BooleanToVisibilityInversedConverter}}"></TextBlock> + </StackPanel> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + <TextBlock>)</TextBlock> + + <StackPanel Margin="5 0 0 0" Orientation="Horizontal" Visibility="{Binding HasOverloads,Converter={StaticResource BooleanToVisibilityConverter}}"> + <TextBlock>(+</TextBlock> + <TextBlock Margin="2 0" Text="{Binding Overloads}"></TextBlock> + <TextBlock>overloads)</TextBlock> + </StackPanel> + </StackPanel> + + <TextBlock Text="{Binding Description}"></TextBlock> + </StackPanel> + </DataTemplate> + </Setter.Value> + </Setter> + </DataTrigger> + + <DataTrigger Binding="{Binding Type}" Value="property"> + <Setter Property="ContentTemplate"> + <Setter.Value> + <DataTemplate> + <StackPanel> + <StackPanel Orientation="Horizontal"> + <TextBlock Text="{Binding ReturnType}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> + <TextBlock Margin="5 0 0 0" Text="{Binding Class}" Foreground="{StaticResource ScriptReferenceTypesBrush}"></TextBlock> + <TextBlock>.</TextBlock> + <TextBlock Text="{Binding Text}"></TextBlock> + <TextBlock Margin="5 0 0 0"> + <Run>{</Run> + <Run Foreground="{StaticResource ScriptKeywordBrush}">get</Run><Run>;</Run> + <Run Foreground="{StaticResource ScriptKeywordBrush}">set</Run><Run>;</Run> + <Run>}</Run> + </TextBlock> + </StackPanel> + + <TextBlock Text="{Binding Description}"></TextBlock> + </StackPanel> + </DataTemplate> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </ContentControl.Style> + + <ContentControl.ContentTemplate> + <DataTemplate> + <ContentPresenter Content="{Binding PopupControl}" /> + </DataTemplate> + </ContentControl.ContentTemplate> + </ContentControl>--> + <ContentPresenter DataContext="{Binding}" Content="{Binding PopupControl}" /> </Border> </DataTemplate> @@ -141,15 +223,6 @@ <Setter Property="Control.Cursor" Value="/Tango.Scripting.Editors;component/themes/RightArrow.cur"/> </Style> - <Style TargetType="{x:Type local:XamlEditor}"> - <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"></Setter> - <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"></Setter> - <Setter Property="FontFamily" Value="Consolas"></Setter> - <Setter Property="FontSize" Value="13"></Setter> - <Setter Property="SyntaxHighlighting" Value="XML"></Setter> - <Setter Property="ShowLineNumbers" Value="True"></Setter> - </Style> - <Style TargetType="{x:Type local:ScriptEditor}"> <Setter Property="Background" Value="{StaticResource ScriptBackgroundBrush}"></Setter> <Setter Property="Foreground" Value="{StaticResource ScriptForegroundBrush}"></Setter> @@ -494,6 +567,4 @@ </Setter.Value> </Setter> </Style> - - </ResourceDictionary> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/XamlEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/XamlEditor.cs deleted file mode 100644 index 22b425ba2..000000000 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/XamlEditor.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace Tango.Scripting.Editors -{ - public class XamlEditor : TextEditor - { - private bool preventCodeUpdate; - - public String Xaml - { - get { return (String)GetValue(XamlProperty); } - set { SetValue(XamlProperty, value); } - } - public static readonly DependencyProperty XamlProperty = - DependencyProperty.Register("Xaml", typeof(String), typeof(XamlEditor), new PropertyMetadata(null, (d, e) => (d as XamlEditor).OnXamlChanged())); - - public XamlEditor() - { - TextChanged += XamlEditor_TextChanged; - } - - private void XamlEditor_TextChanged(object sender, EventArgs e) - { - if (!preventCodeUpdate) - { - preventCodeUpdate = true; - Xaml = Text; - preventCodeUpdate = false; - } - } - - private void OnXamlChanged() - { - if (!preventCodeUpdate) - { - preventCodeUpdate = true; - Text = Xaml; - preventCodeUpdate = false; - } - } - } -} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/app.config b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/app.config index 16d75cf59..d3a17b4de 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/app.config +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/app.config @@ -77,14 +77,6 @@ </dependentAssembly> - <dependentAssembly> - - <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" /> - - <bindingRedirect oldVersion="0.0.0.0-5.0.5.0" newVersion="5.0.5.0" /> - - </dependentAssembly> - </assemblyBinding> </runtime> diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/packages.config b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/packages.config index a0f62a1d4..00eef19db 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/packages.config +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/packages.config @@ -4,7 +4,6 @@ <package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net461" /> <package id="Microsoft.CodeAnalysis.Common" version="2.4.0" targetFramework="net461" /> <package id="Microsoft.CodeAnalysis.CSharp" version="2.4.0" targetFramework="net461" /> - <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> <package id="System.AppContext" version="4.3.0" targetFramework="net461" /> <package id="System.Collections" version="4.3.0" targetFramework="net461" /> <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" /> |
