Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs')
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs1260
1 files changed, 1260 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs
new file mode 100644
index 0000000000..444f64fd04
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditor.cs
@@ -0,0 +1,1260 @@
+//
+// ITextEditor.cs
+//
+// Author:
+// Mike Krüger <mkrueger@xamarin.com>
+//
+// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com)
+//
+// 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 MonoDevelop.Core.Text;
+using System.Collections.Generic;
+using System.Text;
+using MonoDevelop.Ide.Gui;
+using MonoDevelop.Ide.Editor.Extension;
+using System.IO;
+using MonoDevelop.Ide.Editor.Highlighting;
+using Mono.Addins;
+using MonoDevelop.Core;
+using MonoDevelop.Ide.Extensions;
+using System.Linq;
+using MonoDevelop.Components;
+using System.ComponentModel;
+using MonoDevelop.Ide.TypeSystem;
+using System.Threading;
+using MonoDevelop.Ide.Editor.Projection;
+
+namespace MonoDevelop.Ide.Editor
+{
+ public sealed class TextEditor : Control, ITextDocument, IDisposable
+ {
+ readonly ITextEditorImpl textEditorImpl;
+ IReadonlyTextDocument ReadOnlyTextDocument { get { return textEditorImpl.Document; } }
+ ITextDocument ReadWriteTextDocument { get { return (ITextDocument)textEditorImpl.Document; } }
+
+ public ITextSourceVersion Version {
+ get {
+ return ReadOnlyTextDocument.Version;
+ }
+ }
+
+ FileTypeCondition fileTypeCondition = new FileTypeCondition ();
+
+ List<TooltipExtensionNode> allProviders = new List<TooltipExtensionNode> ();
+
+ void OnTooltipProviderChanged (object s, ExtensionNodeEventArgs a)
+ {
+ TooltipProvider provider;
+ try {
+ var extensionNode = a.ExtensionNode as TooltipExtensionNode;
+ allProviders.Add (extensionNode);
+ if (extensionNode.IsValidFor (MimeType))
+ return;
+ provider = (TooltipProvider) extensionNode.CreateInstance ();
+ } catch (Exception e) {
+ LoggingService.LogError ("Can't create tooltip provider:"+ a.ExtensionNode, e);
+ return;
+ }
+ if (a.Change == ExtensionChange.Add) {
+ textEditorImpl.AddTooltipProvider (provider);
+ } else {
+ textEditorImpl.RemoveTooltipProvider (provider);
+ }
+ }
+
+ public event EventHandler SelectionChanged {
+ add { textEditorImpl.SelectionChanged += value; }
+ remove { textEditorImpl.SelectionChanged -= value; }
+ }
+
+ public event EventHandler CaretPositionChanged {
+ add { textEditorImpl.CaretPositionChanged += value; }
+ remove { textEditorImpl.CaretPositionChanged -= value; }
+ }
+
+ public event EventHandler BeginAtomicUndoOperation {
+ add { textEditorImpl.BeginAtomicUndoOperation += value; }
+ remove { textEditorImpl.BeginAtomicUndoOperation -= value; }
+ }
+
+ public event EventHandler EndAtomicUndoOperation {
+ add { textEditorImpl.EndAtomicUndoOperation += value; }
+ remove { textEditorImpl.EndAtomicUndoOperation -= value; }
+ }
+
+ public event EventHandler<TextChangeEventArgs> TextChanging {
+ add { ReadWriteTextDocument.TextChanging += value; }
+ remove { ReadWriteTextDocument.TextChanging -= value; }
+ }
+
+ public event EventHandler<TextChangeEventArgs> TextChanged {
+ add { ReadWriteTextDocument.TextChanged += value; }
+ remove { ReadWriteTextDocument.TextChanged -= value; }
+ }
+
+ public event EventHandler BeginMouseHover {
+ add { textEditorImpl.BeginMouseHover += value; }
+ remove { textEditorImpl.BeginMouseHover -= value; }
+ }
+
+ public event EventHandler VAdjustmentChanged {
+ add { textEditorImpl.VAdjustmentChanged += value; }
+ remove { textEditorImpl.VAdjustmentChanged -= value; }
+ }
+
+ public event EventHandler HAdjustmentChanged {
+ add { textEditorImpl.HAdjustmentChanged += value; }
+ remove { textEditorImpl.HAdjustmentChanged -= value; }
+ }
+ public char this[int offset] {
+ get {
+ return ReadOnlyTextDocument [offset];
+ }
+ set {
+ ReadWriteTextDocument [offset] = value;
+ }
+ }
+
+// public event EventHandler<LineEventArgs> LineChanged {
+// add { textEditorImpl.LineChanged += value; }
+// remove { textEditorImpl.LineChanged -= value; }
+// }
+//
+// public event EventHandler<LineEventArgs> LineInserted {
+// add { textEditorImpl.LineInserted += value; }
+// remove { textEditorImpl.LineInserted -= value; }
+// }
+//
+// public event EventHandler<LineEventArgs> LineRemoved {
+// add { textEditorImpl.LineRemoved += value; }
+// remove { textEditorImpl.LineRemoved -= value; }
+// }
+
+ public ITextEditorOptions Options {
+ get {
+ return textEditorImpl.Options;
+ }
+ set {
+ textEditorImpl.Options = value;
+ OnOptionsChanged (EventArgs.Empty);
+ }
+ }
+
+ public event EventHandler OptionsChanged;
+
+ void OnOptionsChanged (EventArgs e)
+ {
+ var handler = OptionsChanged;
+ if (handler != null)
+ handler (this, e);
+ }
+
+ public EditMode EditMode {
+ get {
+ return textEditorImpl.EditMode;
+ }
+ }
+
+ public DocumentLocation CaretLocation {
+ get {
+ return textEditorImpl.CaretLocation;
+ }
+ set {
+ textEditorImpl.CaretLocation = value;
+ }
+ }
+
+ public SemanticHighlighting SemanticHighlighting {
+ get {
+ return textEditorImpl.SemanticHighlighting;
+ }
+ set {
+ textEditorImpl.SemanticHighlighting = value;
+ }
+ }
+
+ public int CaretLine {
+ get {
+ return CaretLocation.Line;
+ }
+ set {
+ CaretLocation = new DocumentLocation (value, CaretColumn);
+ }
+ }
+
+ public int CaretColumn {
+ get {
+ return CaretLocation.Column;
+ }
+ set {
+ CaretLocation = new DocumentLocation (CaretLine, value);
+ }
+ }
+
+ public int CaretOffset {
+ get {
+ return textEditorImpl.CaretOffset;
+ }
+ set {
+ textEditorImpl.CaretOffset = value;
+ }
+ }
+
+ public bool IsReadOnly {
+ get {
+ return ReadOnlyTextDocument.IsReadOnly;
+ }
+ set {
+ ReadWriteTextDocument.IsReadOnly = value;
+ }
+ }
+
+ public bool IsSomethingSelected {
+ get {
+ return textEditorImpl.IsSomethingSelected;
+ }
+ }
+
+ public SelectionMode SelectionMode {
+ get {
+ return textEditorImpl.SelectionMode;
+ }
+ }
+
+ public ISegment SelectionRange {
+ get {
+ return textEditorImpl.SelectionRange;
+ }
+ set {
+ textEditorImpl.SelectionRange = value;
+ }
+ }
+
+ public DocumentRegion SelectionRegion {
+ get {
+ return textEditorImpl.SelectionRegion;
+ }
+ set {
+ textEditorImpl.SelectionRegion = value;
+ }
+ }
+
+ public int SelectionAnchorOffset {
+ get {
+ return textEditorImpl.SelectionAnchorOffset;
+ }
+ set {
+ textEditorImpl.SelectionAnchorOffset = value;
+ }
+ }
+
+ public int SelectionLeadOffset {
+ get {
+ return textEditorImpl.SelectionLeadOffset;
+ }
+ set {
+ textEditorImpl.SelectionLeadOffset = value;
+ }
+ }
+
+ public string SelectedText {
+ get {
+ return IsSomethingSelected ? ReadOnlyTextDocument.GetTextAt (SelectionRange) : null;
+ }
+ set {
+ var selection = SelectionRange;
+ ReplaceText (selection, value);
+ SelectionRange = new TextSegment (selection.Offset, value.Length);
+ }
+ }
+
+ public bool IsInAtomicUndo {
+ get {
+ return ReadWriteTextDocument.IsInAtomicUndo;
+ }
+ }
+
+ public double LineHeight {
+ get {
+ return textEditorImpl.LineHeight;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the type of the MIME.
+ /// </summary>
+ /// <value>The type of the MIME.</value>
+ public string MimeType {
+ get {
+ return ReadOnlyTextDocument.MimeType;
+ }
+ set {
+ ReadWriteTextDocument.MimeType = value;
+ }
+ }
+
+ public event EventHandler MimeTypeChanged {
+ add { ReadWriteTextDocument.MimeTypeChanged += value; }
+ remove { ReadWriteTextDocument.MimeTypeChanged -= value; }
+ }
+
+ public string Text {
+ get {
+ return ReadOnlyTextDocument.Text;
+ }
+ set {
+ ReadWriteTextDocument.Text = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets the eol marker. On a text editor always use that and not GetEolMarker.
+ /// The EOL marker of the document may get overwritten my the one from the options.
+ /// </summary>
+ public string EolMarker {
+ get {
+ if (Options.OverrideDocumentEolMarker)
+ return Options.DefaultEolMarker;
+ return ReadOnlyTextDocument.GetEolMarker ();
+ }
+ }
+
+ public bool UseBOM {
+ get {
+ return ReadOnlyTextDocument.UseBOM;
+ }
+ set {
+ ReadWriteTextDocument.UseBOM = value;
+ }
+ }
+
+ public Encoding Encoding {
+ get {
+ return ReadOnlyTextDocument.Encoding;
+ }
+ set {
+ ReadWriteTextDocument.Encoding = value;
+ }
+ }
+
+ public int LineCount {
+ get {
+ return ReadOnlyTextDocument.LineCount;
+ }
+ }
+
+ /// <summary>
+ /// Gets the name of the file the document is stored in.
+ /// Could also be a non-existent dummy file name or null if no name has been set.
+ /// </summary>
+ public FilePath FileName {
+ get {
+ return ReadOnlyTextDocument.FileName;
+ }
+ set {
+ ReadWriteTextDocument.FileName = value;
+ }
+ }
+
+ public event EventHandler FileNameChanged {
+ add {
+ ReadWriteTextDocument.FileNameChanged += value;
+ }
+ remove {
+ ReadWriteTextDocument.FileNameChanged -= value;
+ }
+ }
+
+ public int Length {
+ get {
+ return ReadOnlyTextDocument.Length;
+ }
+ }
+
+ public double ZoomLevel {
+ get {
+ return textEditorImpl.ZoomLevel;
+ }
+ set {
+ textEditorImpl.ZoomLevel = value;
+ }
+ }
+
+ public event EventHandler ZoomLevelChanged {
+ add {
+ textEditorImpl.ZoomLevelChanged += value;
+ }
+ remove {
+ textEditorImpl.ZoomLevelChanged -= value;
+ }
+ }
+
+ public IDisposable OpenUndoGroup ()
+ {
+ return ReadWriteTextDocument.OpenUndoGroup ();
+ }
+
+ public void SetSelection (int anchorOffset, int leadOffset)
+ {
+ textEditorImpl.SetSelection (anchorOffset, leadOffset);
+ }
+
+ public void SetSelection (DocumentLocation anchor, DocumentLocation lead)
+ {
+ SetSelection (LocationToOffset (anchor), LocationToOffset (lead));
+ }
+
+ public void SetCaretLocation (DocumentLocation location, bool usePulseAnimation = false)
+ {
+ CaretLocation = location;
+ ScrollTo (CaretLocation);
+ if (usePulseAnimation)
+ StartCaretPulseAnimation ();
+ }
+
+ public void SetCaretLocation (int line, int col, bool usePulseAnimation = false)
+ {
+ CaretLocation = new DocumentLocation (line, col);
+ CenterTo (CaretLocation);
+ if (usePulseAnimation)
+ StartCaretPulseAnimation ();
+ }
+
+ public void ClearSelection ()
+ {
+ textEditorImpl.ClearSelection ();
+ }
+
+ public void CenterToCaret ()
+ {
+ textEditorImpl.CenterToCaret ();
+ }
+
+ public void StartCaretPulseAnimation ()
+ {
+ textEditorImpl.StartCaretPulseAnimation ();
+ }
+
+ public int EnsureCaretIsNotVirtual ()
+ {
+ return textEditorImpl.EnsureCaretIsNotVirtual ();
+ }
+
+ public void FixVirtualIndentation ()
+ {
+ textEditorImpl.FixVirtualIndentation ();
+ }
+
+ public void RunWhenLoaded (Action action)
+ {
+ if (action == null)
+ throw new ArgumentNullException ("action");
+ textEditorImpl.RunWhenLoaded (action);
+ }
+
+ public string FormatString (DocumentLocation insertPosition, string code)
+ {
+ return textEditorImpl.FormatString (LocationToOffset (insertPosition), code);
+ }
+
+ public string FormatString (int offset, string code)
+ {
+ return textEditorImpl.FormatString (offset, code);
+ }
+
+ public void StartInsertionMode (InsertionModeOptions insertionModeOptions)
+ {
+ if (insertionModeOptions == null)
+ throw new ArgumentNullException ("insertionModeOptions");
+ textEditorImpl.StartInsertionMode (insertionModeOptions);
+ }
+
+ public void StartTextLinkMode (TextLinkModeOptions textLinkModeOptions)
+ {
+ if (textLinkModeOptions == null)
+ throw new ArgumentNullException ("textLinkModeOptions");
+ textEditorImpl.StartTextLinkMode (textLinkModeOptions);
+ }
+
+ public void InsertAtCaret (string text)
+ {
+ InsertText (CaretOffset, text);
+ }
+
+ public DocumentLocation PointToLocation (double xp, double yp, bool endAtEol = false)
+ {
+ return textEditorImpl.PointToLocation (xp, yp, endAtEol);
+ }
+
+ public Xwt.Point LocationToPoint (DocumentLocation location)
+ {
+ return textEditorImpl.LocationToPoint (location.Line, location.Column);
+ }
+
+ public Xwt.Point LocationToPoint (int line, int column)
+ {
+ return textEditorImpl.LocationToPoint (line, column);
+ }
+
+ public string GetLineText (int line, bool includeDelimiter = false)
+ {
+ var segment = GetLine (line);
+ return GetTextAt (includeDelimiter ? segment.SegmentIncludingDelimiter : segment);
+ }
+
+ public int LocationToOffset (int line, int column)
+ {
+ return ReadOnlyTextDocument.LocationToOffset (new DocumentLocation (line, column));
+ }
+
+ public int LocationToOffset (DocumentLocation location)
+ {
+ return ReadOnlyTextDocument.LocationToOffset (location);
+ }
+
+ public DocumentLocation OffsetToLocation (int offset)
+ {
+ return ReadOnlyTextDocument.OffsetToLocation (offset);
+ }
+
+ public void InsertText (int offset, string text)
+ {
+ ReadWriteTextDocument.InsertText (offset, text);
+ }
+
+ public void InsertText (int offset, ITextSource text)
+ {
+ ReadWriteTextDocument.InsertText (offset, text);
+ }
+
+ public void RemoveText (int offset, int count)
+ {
+ RemoveText (new TextSegment (offset, count));
+ }
+
+ public void RemoveText (ISegment segment)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ ReadWriteTextDocument.RemoveText (segment);
+ }
+
+ public void ReplaceText (int offset, int count, string value)
+ {
+ ReadWriteTextDocument.ReplaceText (offset, count, value);
+ }
+
+ public void ReplaceText (int offset, int count, ITextSource value)
+ {
+ ReadWriteTextDocument.ReplaceText (offset, count, value);
+ }
+
+ public void ReplaceText (ISegment segment, string value)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ ReadWriteTextDocument.ReplaceText (segment.Offset, segment.Length, value);
+ }
+
+ public void ReplaceText (ISegment segment, ITextSource value)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ ReadWriteTextDocument.ReplaceText (segment.Offset, segment.Length, value);
+ }
+
+ public IDocumentLine GetLine (int lineNumber)
+ {
+ return ReadOnlyTextDocument.GetLine (lineNumber);
+ }
+
+ public IDocumentLine GetLineByOffset (int offset)
+ {
+ return ReadOnlyTextDocument.GetLineByOffset (offset);
+ }
+
+ public int OffsetToLineNumber (int offset)
+ {
+ return ReadOnlyTextDocument.OffsetToLineNumber (offset);
+ }
+
+ public void AddMarker (IDocumentLine line, ITextLineMarker lineMarker)
+ {
+ if (line == null)
+ throw new ArgumentNullException ("line");
+ if (lineMarker == null)
+ throw new ArgumentNullException ("lineMarker");
+ textEditorImpl.AddMarker (line, lineMarker);
+ }
+
+ public void AddMarker (int lineNumber, ITextLineMarker lineMarker)
+ {
+ if (lineMarker == null)
+ throw new ArgumentNullException ("lineMarker");
+ AddMarker (GetLine (lineNumber), lineMarker);
+ }
+
+ public void RemoveMarker (ITextLineMarker lineMarker)
+ {
+ if (lineMarker == null)
+ throw new ArgumentNullException ("lineMarker");
+ textEditorImpl.RemoveMarker (lineMarker);
+ }
+
+ public IEnumerable<ITextLineMarker> GetLineMarkers (IDocumentLine line)
+ {
+ if (line == null)
+ throw new ArgumentNullException ("line");
+ return textEditorImpl.GetLineMarkers (line);
+ }
+
+ public IEnumerable<ITextSegmentMarker> GetTextSegmentMarkersAt (ISegment segment)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ return textEditorImpl.GetTextSegmentMarkersAt (segment);
+ }
+
+ public IEnumerable<ITextSegmentMarker> GetTextSegmentMarkersAt (int offset)
+ {
+ return textEditorImpl.GetTextSegmentMarkersAt (offset);
+ }
+
+ public void AddMarker (ITextSegmentMarker marker)
+ {
+ if (marker == null)
+ throw new ArgumentNullException ("marker");
+ textEditorImpl.AddMarker (marker);
+ }
+
+ public bool RemoveMarker (ITextSegmentMarker marker)
+ {
+ if (marker == null)
+ throw new ArgumentNullException ("marker");
+ return textEditorImpl.RemoveMarker (marker);
+ }
+
+ public void SetFoldings (IEnumerable<IFoldSegment> foldings)
+ {
+ if (foldings == null)
+ throw new ArgumentNullException ("foldings");
+ textEditorImpl.SetFoldings (foldings);
+ }
+
+
+ public IEnumerable<IFoldSegment> GetFoldingsContaining (int offset)
+ {
+ return textEditorImpl.GetFoldingsContaining (offset);
+ }
+
+ public IEnumerable<IFoldSegment> GetFoldingsIn (ISegment segment)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ return textEditorImpl.GetFoldingsIn (segment.Offset, segment.Length);
+ }
+
+ /// <summary>
+ /// Gets a character at the specified position in the document.
+ /// </summary>
+ /// <paramref name="offset">The index of the character to get.</paramref>
+ /// <exception cref="ArgumentOutOfRangeException">Offset is outside the valid range (0 to TextLength-1).</exception>
+ /// <returns>The character at the specified position.</returns>
+ /// <remarks>This is the same as Text[offset], but is more efficient because
+ /// it doesn't require creating a String object.</remarks>
+ public char GetCharAt (int offset)
+ {
+ return ReadOnlyTextDocument.GetCharAt (offset);
+ }
+
+ public string GetTextAt (int offset, int length)
+ {
+ return ReadOnlyTextDocument.GetTextAt (offset, length);
+ }
+
+ public string GetTextAt (ISegment segment)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ return ReadOnlyTextDocument.GetTextAt (segment);
+ }
+
+ public IReadonlyTextDocument CreateDocumentSnapshot ()
+ {
+ return ReadWriteTextDocument.CreateDocumentSnapshot ();
+ }
+
+ public string GetVirtualIndentationString (int lineNumber)
+ {
+ if (lineNumber < 1 || lineNumber > LineCount)
+ throw new ArgumentOutOfRangeException ("lineNumber");
+ return textEditorImpl.GetVirtualIndentationString (lineNumber);
+ }
+
+ public string GetVirtualIndentationString (IDocumentLine line)
+ {
+ if (line == null)
+ throw new ArgumentNullException ("line");
+ return textEditorImpl.GetVirtualIndentationString (line.LineNumber);
+ }
+
+ public int GetVirtualIndentationColumn (int lineNumber)
+ {
+ if (lineNumber < 1 || lineNumber > LineCount)
+ throw new ArgumentOutOfRangeException ("lineNumber");
+ return 1 + textEditorImpl.GetVirtualIndentationString (lineNumber).Length;
+ }
+
+ public int GetVirtualIndentationColumn (IDocumentLine line)
+ {
+ if (line == null)
+ throw new ArgumentNullException ("line");
+ return 1 + textEditorImpl.GetVirtualIndentationString (line.LineNumber).Length;
+ }
+
+ public TextReader CreateReader ()
+ {
+ return ReadOnlyTextDocument.CreateReader ();
+ }
+
+ public TextReader CreateReader (int offset, int length)
+ {
+ return ReadOnlyTextDocument.CreateReader (offset, length);
+ }
+
+ public ITextSource CreateSnapshot ()
+ {
+ return ReadOnlyTextDocument.CreateSnapshot ();
+ }
+
+ public ITextSource CreateSnapshot (int offset, int length)
+ {
+ return ReadOnlyTextDocument.CreateSnapshot (offset, length);
+ }
+
+ public ITextSource CreateSnapshot (ISegment segment)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ return ReadOnlyTextDocument.CreateSnapshot (segment.Offset, segment.Length);
+ }
+
+ public void WriteTextTo (TextWriter writer)
+ {
+ if (writer == null)
+ throw new ArgumentNullException ("writer");
+ ReadOnlyTextDocument.WriteTextTo (writer);
+ }
+
+ public void WriteTextTo (TextWriter writer, int offset, int length)
+ {
+ if (writer == null)
+ throw new ArgumentNullException ("writer");
+ ReadOnlyTextDocument.WriteTextTo (writer, offset, length);
+ }
+
+ public void ScrollTo (int offset)
+ {
+ textEditorImpl.ScrollTo (offset);
+ }
+
+ public void ScrollTo (DocumentLocation loc)
+ {
+ ScrollTo (LocationToOffset (loc));
+ }
+
+ public void CenterTo (int offset)
+ {
+ textEditorImpl.CenterTo (offset);
+ }
+
+ public void CenterTo (DocumentLocation loc)
+ {
+ CenterTo (LocationToOffset (loc));
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Advanced)]
+ public void SetIndentationTracker (IndentationTracker indentationTracker)
+ {
+ textEditorImpl.SetIndentationTracker (indentationTracker);
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Advanced)]
+ public void SetSelectionSurroundingProvider (SelectionSurroundingProvider surroundingProvider)
+ {
+ textEditorImpl.SetSelectionSurroundingProvider (surroundingProvider);
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Advanced)]
+ public void SetTextPasteHandler (TextPasteHandler textPasteHandler)
+ {
+ textEditorImpl.SetTextPasteHandler (textPasteHandler);
+ }
+
+ public IList<SkipChar> SkipChars {
+ get {
+ return textEditorImpl.SkipChars;
+ }
+ }
+
+ /// <summary>
+ /// Skip chars are
+ /// </summary>
+ public void AddSkipChar (int offset, char ch)
+ {
+ textEditorImpl.AddSkipChar (offset, ch);
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing) {
+ DetachExtensionChain ();
+ textEditorImpl.Dispose ();
+ }
+ base.Dispose (disposing);
+ }
+
+ protected override object CreateNativeWidget ()
+ {
+ return textEditorImpl.CreateNativeControl ();
+ }
+
+ #region Internal API
+ ExtensionContext extensionContext;
+
+ internal ExtensionContext ExtensionContext {
+ get {
+ return extensionContext;
+ }
+ set {
+ if (extensionContext != null) {
+ extensionContext.RemoveExtensionNodeHandler ("MonoDevelop/SourceEditor2/TooltipProviders", OnTooltipProviderChanged);
+// textEditorImpl.ClearTooltipProviders ();
+ }
+ extensionContext = value;
+ if (extensionContext != null)
+ extensionContext.AddExtensionNodeHandler ("MonoDevelop/SourceEditor2/TooltipProviders", OnTooltipProviderChanged);
+ }
+ }
+
+ internal IEditorActionHost EditorActionHost {
+ get {
+ return textEditorImpl.Actions;
+ }
+ }
+
+ internal ITextMarkerFactory TextMarkerFactory {
+ get {
+ return textEditorImpl.TextMarkerFactory;
+ }
+ }
+
+ internal TextEditor (ITextEditorImpl textEditorImpl)
+ {
+ if (textEditorImpl == null)
+ throw new ArgumentNullException ("textEditorImpl");
+ this.textEditorImpl = textEditorImpl;
+ commandRouter = new InternalCommandRouter (this);
+ fileTypeCondition.SetFileName (FileName);
+ ExtensionContext = AddinManager.CreateExtensionContext ();
+ ExtensionContext.RegisterCondition ("FileType", fileTypeCondition);
+
+ FileNameChanged += delegate {
+ fileTypeCondition.SetFileName (FileName);
+ };
+
+ MimeTypeChanged += delegate {
+ textEditorImpl.ClearTooltipProviders ();
+ foreach (var extensionNode in allProviders) {
+ if (extensionNode.IsValidFor (MimeType))
+ textEditorImpl.AddTooltipProvider ((TooltipProvider) extensionNode.CreateInstance ());
+ }
+ };
+ }
+
+ TextEditorViewContent viewContent;
+ internal IViewContent GetViewContent ()
+ {
+ if (viewContent == null) {
+ viewContent = new TextEditorViewContent (this, textEditorImpl);
+ }
+
+ return viewContent;
+ }
+
+ internal IFoldSegment CreateFoldSegment (int offset, int length, bool isFolded = false)
+ {
+ return textEditorImpl.CreateFoldSegment (offset, length, isFolded);
+ }
+ #endregion
+
+ #region Editor extensions
+ InternalCommandRouter commandRouter;
+ class InternalCommandRouter : MonoDevelop.Components.Commands.IMultiCastCommandRouter
+ {
+ readonly TextEditor editor;
+
+ public InternalCommandRouter (TextEditor editor)
+ {
+ this.editor = editor;
+ }
+
+ #region IMultiCastCommandRouter implementation
+
+ System.Collections.IEnumerable MonoDevelop.Components.Commands.IMultiCastCommandRouter.GetCommandTargets ()
+ {
+ yield return editor.textEditorImpl;
+ yield return editor.textEditorImpl.EditorExtension;
+ }
+ #endregion
+ }
+
+ internal object CommandRouter {
+ get {
+ return commandRouter;
+ }
+ }
+
+ DocumentContext documentContext;
+ internal DocumentContext DocumentContext {
+ get {
+ return documentContext;
+ }
+ set {
+ documentContext = value;
+ OnDocumentContextChanged (EventArgs.Empty);
+ }
+ }
+
+ public event EventHandler DocumentContextChanged;
+
+ void OnDocumentContextChanged (EventArgs e)
+ {
+ if (DocumentContext != null) {
+ textEditorImpl.SetQuickTaskProviders (DocumentContext.GetContents<IQuickTaskProvider> ());
+ textEditorImpl.SetUsageTaskProviders (DocumentContext.GetContents<UsageProviderEditorExtension> ());
+ } else {
+ textEditorImpl.SetQuickTaskProviders (Enumerable.Empty<IQuickTaskProvider> ());
+ textEditorImpl.SetUsageTaskProviders (Enumerable.Empty<UsageProviderEditorExtension> ());
+ }
+ var handler = DocumentContextChanged;
+ if (handler != null)
+ handler (this, e);
+ }
+
+ internal void InitializeExtensionChain (DocumentContext documentContext)
+ {
+ if (documentContext == null)
+ throw new ArgumentNullException ("documentContext");
+ DetachExtensionChain ();
+ var extensions = ExtensionContext.GetExtensionNodes ("/MonoDevelop/Ide/TextEditorExtensions", typeof(TextEditorExtensionNode));
+ TextEditorExtension last = null;
+ var mimetypeChain = DesktopService.GetMimeTypeInheritanceChainForFile (FileName).ToArray ();
+ foreach (TextEditorExtensionNode extNode in extensions) {
+ if (!extNode.Supports (FileName, mimetypeChain))
+ continue;
+ TextEditorExtension ext;
+ try {
+ var instance = extNode.CreateInstance ();
+ ext = instance as TextEditorExtension;
+ if (ext == null)
+ continue;
+ } catch (Exception e) {
+ LoggingService.LogError ("Error while creating text editor extension :" + extNode.Id + "(" + extNode.Type +")", e);
+ continue;
+ }
+ if (ext.IsValidInContext (documentContext)) {
+ if (last != null) {
+ last.Next = ext;
+ last = ext;
+ } else {
+ textEditorImpl.EditorExtension = last = ext;
+ }
+ ext.Initialize (this, documentContext);
+ }
+ }
+ this.DocumentContext = documentContext;
+ }
+
+ void DetachExtensionChain ()
+ {
+ var editorExtension = textEditorImpl.EditorExtension;
+ while (editorExtension != null) {
+ try {
+ editorExtension.Dispose ();
+ } catch (Exception ex) {
+ LoggingService.LogError ("Exception while disposing extension:" + editorExtension, ex);
+ }
+ editorExtension = editorExtension.Next;
+ }
+ textEditorImpl.EditorExtension = null;
+ }
+
+ public T GetContent<T> () where T : class
+ {
+ T result = textEditorImpl as T;
+ if (result != null)
+ return result;
+ var ext = textEditorImpl.EditorExtension;
+ while (ext != null) {
+ result = ext as T;
+ if (result != null)
+ return result;
+ ext = ext.Next;
+ }
+ return null;
+ }
+
+ public IEnumerable<T> GetContents<T> () where T : class
+ {
+ T result = textEditorImpl as T;
+ if (result != null)
+ yield return result;
+ var ext = textEditorImpl.EditorExtension;
+ while (ext != null) {
+ result = ext as T;
+ if (result != null)
+ yield return result;
+ ext = ext.Next;
+ }
+ }
+ #endregion
+
+ public string GetPangoMarkup (int offset, int length)
+ {
+ return textEditorImpl.GetPangoMarkup (offset, length);
+ }
+
+ public string GetPangoMarkup (ISegment segment)
+ {
+ if (segment == null)
+ throw new ArgumentNullException ("segment");
+ return textEditorImpl.GetPangoMarkup (segment.Offset, segment.Length);
+ }
+
+ public static implicit operator Microsoft.CodeAnalysis.Text.SourceText (TextEditor editor)
+ {
+ return new MonoDevelopSourceText (editor);
+ }
+
+
+ #region Annotations
+ // Annotations: points either null (no annotations), to the single annotation,
+ // or to an AnnotationList.
+ // Once it is pointed at an AnnotationList, it will never change (this allows thread-safety support by locking the list)
+
+ object annotations;
+ sealed class AnnotationList : List<object>, ICloneable
+ {
+ // There are two uses for this custom list type:
+ // 1) it's private, and thus (unlike List<object>) cannot be confused with real annotations
+ // 2) It allows us to simplify the cloning logic by making the list behave the same as a clonable annotation.
+ public AnnotationList (int initialCapacity) : base(initialCapacity)
+ {
+ }
+
+ public object Clone ()
+ {
+ lock (this) {
+ AnnotationList copy = new AnnotationList (this.Count);
+ for (int i = 0; i < this.Count; i++) {
+ object obj = this [i];
+ ICloneable c = obj as ICloneable;
+ copy.Add (c != null ? c.Clone () : obj);
+ }
+ return copy;
+ }
+ }
+ }
+
+ public void AddAnnotation (object annotation)
+ {
+ if (annotation == null)
+ throw new ArgumentNullException ("annotation");
+ retry: // Retry until successful
+ object oldAnnotation = Interlocked.CompareExchange (ref this.annotations, annotation, null);
+ if (oldAnnotation == null) {
+ return; // we successfully added a single annotation
+ }
+ AnnotationList list = oldAnnotation as AnnotationList;
+ if (list == null) {
+ // we need to transform the old annotation into a list
+ list = new AnnotationList (4);
+ list.Add (oldAnnotation);
+ list.Add (annotation);
+ if (Interlocked.CompareExchange (ref this.annotations, list, oldAnnotation) != oldAnnotation) {
+ // the transformation failed (some other thread wrote to this.annotations first)
+ goto retry;
+ }
+ } else {
+ // once there's a list, use simple locking
+ lock (list) {
+ list.Add (annotation);
+ }
+ }
+ }
+
+ public void RemoveAnnotations<T> () where T : class
+ {
+ retry: // Retry until successful
+ object oldAnnotations = this.annotations;
+ var list = oldAnnotations as AnnotationList;
+ if (list != null) {
+ lock (list)
+ list.RemoveAll (obj => obj is T);
+ } else if (oldAnnotations is T) {
+ if (Interlocked.CompareExchange (ref this.annotations, null, oldAnnotations) != oldAnnotations) {
+ // Operation failed (some other thread wrote to this.annotations first)
+ goto retry;
+ }
+ }
+ }
+
+ public T Annotation<T> () where T: class
+ {
+ object annotations = this.annotations;
+ var list = annotations as AnnotationList;
+ if (list != null) {
+ lock (list) {
+ foreach (object obj in list) {
+ T t = obj as T;
+ if (t != null)
+ return t;
+ }
+ return null;
+ }
+ }
+ return annotations as T;
+ }
+
+ /// <summary>
+ /// Gets all annotations stored on this AstNode.
+ /// </summary>
+ public IEnumerable<object> Annotations {
+ get {
+ object annotations = this.annotations;
+ AnnotationList list = annotations as AnnotationList;
+ if (list != null) {
+ lock (list) {
+ return list.ToArray ();
+ }
+ }
+ if (annotations != null)
+ return new [] { annotations };
+ return Enumerable.Empty<object> ();
+ }
+ }
+ #endregion
+
+ List<ProjectedTooltipProvider> projectedProviders = new List<ProjectedTooltipProvider> ();
+ IReadOnlyList<MonoDevelop.Ide.Editor.Projection.Projection> projections = null;
+
+ public void SetOrUpdateProjections (DocumentContext ctx, IReadOnlyList<MonoDevelop.Ide.Editor.Projection.Projection> projections, DisabledProjectionFeatures disabledFeatures = DisabledProjectionFeatures.None)
+ {
+ if (ctx == null)
+ throw new ArgumentNullException ("ctx");
+ if (this.projections != null) {
+ foreach (var projection in this.projections) {
+ projection.Dettach ();
+ }
+ }
+ this.projections = projections;
+ if (projections != null) {
+ foreach (var projection in projections) {
+ projection.Attach (this);
+ }
+ }
+
+ if ((disabledFeatures & DisabledProjectionFeatures.SemanticHighlighting) != DisabledProjectionFeatures.SemanticHighlighting) {
+ if (SemanticHighlighting is ProjectedSemanticHighlighting) {
+ ((ProjectedSemanticHighlighting)SemanticHighlighting).UpdateProjection (projections);
+ } else {
+ SemanticHighlighting = new ProjectedSemanticHighlighting (this, ctx, projections);
+ }
+ }
+
+ if ((disabledFeatures & DisabledProjectionFeatures.Tooltips) != DisabledProjectionFeatures.Tooltips) {
+ projectedProviders.ForEach (textEditorImpl.RemoveTooltipProvider);
+ projectedProviders = new List<ProjectedTooltipProvider> ();
+ foreach (var projection in projections) {
+ foreach (var tp in projection.ProjectedEditor.textEditorImpl.TooltipProvider) {
+ var newProvider = new ProjectedTooltipProvider (this, ctx, projection, tp);
+ projectedProviders.Add (newProvider);
+ textEditorImpl.AddTooltipProvider (newProvider);
+ }
+ }
+ }
+ InitializeProjectionExtensions (ctx, disabledFeatures);
+ }
+
+ bool projectionsAdded = false;
+ void InitializeProjectionExtensions (DocumentContext ctx, DisabledProjectionFeatures disabledFeatures)
+ {
+ if (projectionsAdded) {
+ TextEditorExtension ext = textEditorImpl.EditorExtension;
+ while (ext != null && ext.Next != null) {
+ var pext = ext as IProjectionExtension;
+ if (pext != null) {
+ pext.Projections = projections;
+ }
+ ext = ext.Next;
+ }
+ return;
+ }
+
+ if (projections.Count == 0)
+ return;
+
+ TextEditorExtension lastExtension = textEditorImpl.EditorExtension;
+ while (lastExtension != null && lastExtension.Next != null) {
+ var completionTextEditorExtension = lastExtension.Next as CompletionTextEditorExtension;
+ if (completionTextEditorExtension != null) {
+ var projectedFilterExtension = new ProjectedFilterCompletionTextEditorExtension (completionTextEditorExtension, projections) { Next = completionTextEditorExtension.Next };
+ lastExtension.Next = projectedFilterExtension;
+ projectedFilterExtension.Initialize (this, DocumentContext);
+ }
+ lastExtension = lastExtension.Next;
+ }
+
+ // no extensions -> no projections needed
+ if (textEditorImpl.EditorExtension == null)
+ return;
+
+ if ((disabledFeatures & DisabledProjectionFeatures.Completion) != DisabledProjectionFeatures.Completion) {
+ var projectedCompletionExtension = new ProjectedCompletionExtension (ctx, projections);
+ projectedCompletionExtension.Next = textEditorImpl.EditorExtension;
+
+ textEditorImpl.EditorExtension = projectedCompletionExtension;
+ projectedCompletionExtension.Initialize (this, DocumentContext);
+ }
+ projectionsAdded = true;
+ }
+
+ public void AddOverlay (Control messageOverlayContent, Func<int> sizeFunc)
+ {
+ textEditorImpl.AddOverlay (messageOverlayContent, sizeFunc);
+ }
+
+ public void RemoveOverlay (Control messageOverlayContent)
+ {
+ textEditorImpl.RemoveOverlay (messageOverlayContent);
+ }
+ }
+} \ No newline at end of file