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/TextEditorViewContent.cs')
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs1233
1 files changed, 1233 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs
new file mode 100644
index 0000000000..2305687ba2
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/TextEditorViewContent.cs
@@ -0,0 +1,1233 @@
+//
+// TextEditorViewContent.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.Ide.Gui;
+using MonoDevelop.Projects;
+using MonoDevelop.Ide.Gui.Content;
+using MonoDevelop.Components.Commands;
+using MonoDevelop.Ide.Commands;
+using System.Collections;
+using System.Collections.Generic;
+using MonoDevelop.Ide.TypeSystem;
+using System.IO;
+using MonoDevelop.Core.Text;
+using System.Text;
+using Gtk;
+using ICSharpCode.NRefactory.TypeSystem;
+using System.Linq;
+using MonoDevelop.Ide.Editor.Extension;
+using ICSharpCode.NRefactory.Refactoring;
+using MonoDevelop.Components;
+using MonoDevelop.Core;
+using System.Threading.Tasks;
+using System.Threading;
+using System.Threading;
+using Microsoft.CodeAnalysis;
+using Gdk;
+using MonoDevelop.Ide.CodeFormatting;
+
+namespace MonoDevelop.Ide.Editor
+{
+ /// <summary>
+ /// The TextEditor object needs to be available through IBaseViewContent.GetContent therefore we need to insert a
+ /// decorator in between.
+ /// </summary>
+ class TextEditorViewContent : IViewContent, ICommandRouter, IQuickTaskProvider
+ {
+ readonly TextEditor textEditor;
+ readonly ITextEditorImpl textEditorImpl;
+
+ DocumentContext currentContext;
+ MonoDevelop.Projects.Policies.PolicyContainer policyContainer;
+
+ public TextEditorViewContent (TextEditor textEditor, ITextEditorImpl textEditorImpl)
+ {
+ if (textEditor == null)
+ throw new ArgumentNullException ("textEditor");
+ if (textEditorImpl == null)
+ throw new ArgumentNullException ("textEditorImpl");
+ this.textEditor = textEditor;
+ this.textEditorImpl = textEditorImpl;
+ this.textEditor.MimeTypeChanged += UpdateTextEditorOptions;
+ DefaultSourceEditorOptions.Instance.Changed += UpdateTextEditorOptions;
+ this.textEditor.DocumentContextChanged += delegate {
+ if (currentContext != null)
+ currentContext.DocumentParsed -= HandleDocumentParsed;
+ currentContext = textEditor.DocumentContext;
+ currentContext.DocumentParsed += HandleDocumentParsed;
+ };
+ }
+
+ void HandleDirtyChanged (object sender, EventArgs e)
+ {
+ InformAutoSave ();
+ }
+
+ void HandleTextChanged (object sender, MonoDevelop.Core.Text.TextChangeEventArgs e)
+ {
+ InformAutoSave ();
+ }
+
+ void UpdateTextEditorOptions (object sender, EventArgs e)
+ {
+ UpdateStyleParent (Project, textEditor.MimeType);
+ }
+
+ uint autoSaveTimer = 0;
+
+ void InformAutoSave ()
+ {
+ RemoveAutoSaveTimer ();
+ autoSaveTimer = GLib.Timeout.Add (500, delegate {
+ AutoSave.InformAutoSaveThread (textEditor.CreateSnapshot (), textEditor.FileName, textEditorImpl.IsDirty);
+ autoSaveTimer = 0;
+ return false;
+ });
+ }
+
+
+ void RemoveAutoSaveTimer ()
+ {
+ if (autoSaveTimer == 0)
+ return;
+ GLib.Source.Remove (autoSaveTimer);
+ autoSaveTimer = 0;
+ }
+
+ void RemovePolicyChangeHandler ()
+ {
+ if (policyContainer != null)
+ policyContainer.PolicyChanged -= HandlePolicyChanged;
+ }
+
+ void UpdateStyleParent (MonoDevelop.Projects.Project styleParent, string mimeType)
+ {
+ RemovePolicyChangeHandler ();
+
+ if (string.IsNullOrEmpty (mimeType))
+ mimeType = "text/plain";
+
+ var mimeTypes = DesktopService.GetMimeTypeInheritanceChain (mimeType);
+
+ if (styleParent != null)
+ policyContainer = styleParent.Policies;
+ else
+ policyContainer = MonoDevelop.Projects.Policies.PolicyService.DefaultPolicies;
+ var currentPolicy = policyContainer.Get<TextStylePolicy> (mimeTypes);
+
+ policyContainer.PolicyChanged += HandlePolicyChanged;
+ textEditor.Options = DefaultSourceEditorOptions.Instance.WithTextStyle (currentPolicy);
+ }
+
+ void HandlePolicyChanged (object sender, MonoDevelop.Projects.Policies.PolicyChangedEventArgs args)
+ {
+ var mimeTypes = DesktopService.GetMimeTypeInheritanceChain (textEditor.MimeType);
+ var currentPolicy = policyContainer.Get<TextStylePolicy> (mimeTypes);
+ textEditor.Options = DefaultSourceEditorOptions.Instance.WithTextStyle (currentPolicy);
+ }
+
+ void HandleDocumentParsed (object sender, EventArgs e)
+ {
+ var ctx = (DocumentContext)sender;
+ src.Cancel ();
+ src = new CancellationTokenSource ();
+ var token = src.Token;
+ Task.Run (() => {
+ try {
+ UpdateErrorUndelines (ctx.ParsedDocument, token);
+ UpdateQuickTasks (ctx.ParsedDocument, token);
+ UpdateFoldings (ctx.ParsedDocument, false, token);
+ } catch (OperationCanceledException) {
+ // ignore
+ }
+ }, token);
+ }
+
+ #region Error handling
+ List<IErrorMarker> errors = new List<IErrorMarker> ();
+ uint resetTimerId;
+
+ void RemoveErrorUndelinesResetTimerId ()
+ {
+ if (resetTimerId > 0) {
+ GLib.Source.Remove (resetTimerId);
+ resetTimerId = 0;
+ }
+ }
+
+ void RemoveErrorUnderlines ()
+ {
+ errors.ForEach (err => textEditor.RemoveMarker (err));
+ errors.Clear ();
+ }
+
+ void UnderLineError (MonoDevelop.Ide.TypeSystem.Error info)
+ {
+ var error = TextMarkerFactory.CreateErrorMarker (textEditor, info);
+ textEditor.AddMarker (error);
+ errors.Add (error);
+ }
+
+ async void UpdateErrorUndelines (ParsedDocument parsedDocument, CancellationToken token)
+ {
+ if (!DefaultSourceEditorOptions.Instance.UnderlineErrors || parsedDocument == null)
+ return;
+ try {
+ var errors = await parsedDocument.GetErrorsAsync(token).ConfigureAwait (false);
+ Application.Invoke (delegate {
+ if (token.IsCancellationRequested)
+ return;
+ RemoveErrorUndelinesResetTimerId ();
+ const uint timeout = 500;
+ resetTimerId = GLib.Timeout.Add (timeout, delegate {
+ if (token.IsCancellationRequested) {
+ resetTimerId = 0;
+ return false;
+ }
+ RemoveErrorUnderlines ();
+ // Else we underline the error
+ if (errors != null) {
+ foreach (var error in errors) {
+ UnderLineError (error);
+ }
+ }
+ resetTimerId = 0;
+ return false;
+ });
+ });
+ } catch (OperationCanceledException) {
+ // ignore
+ }
+ }
+ #endregion
+ CancellationTokenSource src = new CancellationTokenSource ();
+ void UpdateFoldings (ParsedDocument parsedDocument, bool firstTime = false, CancellationToken token = default (CancellationToken))
+ {
+ if (parsedDocument == null || !textEditor.Options.ShowFoldMargin)
+ return;
+ // don't update parsed documents that contain errors - the foldings from there may be invalid.
+ if (parsedDocument.HasErrors)
+ return;
+ var caretLocation = textEditor.CaretLocation;
+ try {
+ var foldSegments = new List<IFoldSegment> ();
+
+ foreach (FoldingRegion region in parsedDocument.GetFoldingsAsync(token).Result) {
+ if (token.IsCancellationRequested)
+ return;
+ var type = FoldingType.Unknown;
+ bool setFolded = false;
+ bool folded = false;
+ //decide whether the regions should be folded by default
+ switch (region.Type) {
+ case FoldType.Member:
+ type = FoldingType.TypeMember;
+ break;
+ case FoldType.Type:
+ type = FoldingType.TypeDefinition;
+ break;
+ case FoldType.UserRegion:
+ type = FoldingType.Region;
+ setFolded = DefaultSourceEditorOptions.Instance.DefaultRegionsFolding;
+ folded = true;
+ break;
+ case FoldType.Comment:
+ type = FoldingType.Comment;
+ setFolded = DefaultSourceEditorOptions.Instance.DefaultCommentFolding;
+ folded = true;
+ break;
+ case FoldType.CommentInsideMember:
+ type = FoldingType.Comment;
+ setFolded = DefaultSourceEditorOptions.Instance.DefaultCommentFolding;
+ folded = false;
+ break;
+ case FoldType.Undefined:
+ setFolded = true;
+ folded = region.IsFoldedByDefault;
+ break;
+ }
+ var start = textEditor.LocationToOffset (region.Region.Begin);
+ var end = textEditor.LocationToOffset (region.Region.End);
+ var marker = textEditor.CreateFoldSegment (start, end - start);
+ foldSegments.Add (marker);
+ marker.CollapsedText = region.Name;
+ marker.FoldingType = type;
+ //and, if necessary, set its fold state
+ if (marker != null && setFolded && firstTime) {
+ // only fold on document open, later added folds are NOT folded by default.
+ marker.IsCollapsed = folded;
+ continue;
+ }
+ if (marker != null && region.Region.Contains (caretLocation.Line, caretLocation.Column))
+ marker.IsCollapsed = false;
+ }
+ if (firstTime) {
+ textEditor.SetFoldings (foldSegments);
+ } else {
+ Application.Invoke (delegate {
+ if (!token.IsCancellationRequested)
+ textEditor.SetFoldings (foldSegments);
+ });
+ }
+ } catch (Exception ex) {
+ LoggingService.LogError ("Unhandled exception in ParseInformationUpdaterWorkerThread", ex);
+ }
+ }
+
+ void RunFirstTimeFoldUpdate (string text)
+ {
+ if (string.IsNullOrEmpty (text))
+ return;
+ ParsedDocument parsedDocument = null;
+
+ var foldingParser = TypeSystemService.GetFoldingParser (textEditor.MimeType);
+ if (foldingParser != null) {
+ parsedDocument = foldingParser.Parse (textEditor.FileName, text);
+ } else {
+ var normalParser = TypeSystemService.GetParser (textEditor.MimeType);
+ if (normalParser != null) {
+ parsedDocument = normalParser.Parse (new MonoDevelop.Ide.TypeSystem.ParseOptions { FileName = textEditor.FileName, Content = new StringTextSource (text) }).Result;
+ }
+ }
+ if (parsedDocument != null) {
+ UpdateFoldings (parsedDocument, true);
+ }
+ }
+
+
+ #region IViewFContent implementation
+
+ event EventHandler IViewContent.ContentNameChanged {
+ add {
+ textEditorImpl.ContentNameChanged += value;
+ }
+ remove {
+ textEditorImpl.ContentNameChanged -= value;
+ }
+ }
+
+ event EventHandler IViewContent.ContentChanged {
+ add {
+ textEditorImpl.ContentChanged += value;
+ }
+ remove {
+ textEditorImpl.ContentChanged -= value;
+ }
+ }
+
+ event EventHandler IViewContent.DirtyChanged {
+ add {
+ textEditorImpl.DirtyChanged += value;
+ }
+ remove {
+ textEditorImpl.DirtyChanged -= value;
+ }
+ }
+
+ event EventHandler IViewContent.BeforeSave {
+ add {
+ textEditorImpl.BeforeSave += value;
+ }
+ remove {
+ textEditorImpl.BeforeSave -= value;
+ }
+ }
+
+ void IViewContent.Load (FileOpenInformation fileOpenInformation)
+ {
+ this.textEditorImpl.DirtyChanged -= HandleDirtyChanged;
+ this.textEditor.TextChanged -= HandleTextChanged;
+ textEditorImpl.Load (fileOpenInformation);
+ RunFirstTimeFoldUpdate (textEditor.Text);
+ this.textEditor.TextChanged += HandleTextChanged;
+ this.textEditorImpl.DirtyChanged += HandleDirtyChanged;
+ }
+
+ void IViewContent.Load (string fileName)
+ {
+ this.textEditorImpl.DirtyChanged -= HandleDirtyChanged;
+ this.textEditor.TextChanged -= HandleTextChanged;
+ textEditorImpl.Load (new FileOpenInformation (fileName));
+ RunFirstTimeFoldUpdate (textEditor.Text);
+ this.textEditor.TextChanged += HandleTextChanged;
+ this.textEditorImpl.DirtyChanged += HandleDirtyChanged;
+ }
+
+ void IViewContent.LoadNew (System.IO.Stream content, string mimeType)
+ {
+ textEditor.MimeType = mimeType;
+ string text = null;
+ if (content != null) {
+ Encoding encoding;
+ bool hadBom;
+ text = TextFileUtility.GetText (content, out encoding, out hadBom);
+ textEditor.Text = text;
+ textEditor.Encoding = encoding;
+ textEditor.UseBOM = hadBom;
+ }
+ RunFirstTimeFoldUpdate (text);
+ textEditorImpl.InformLoadComplete ();
+ }
+
+ void IViewContent.Save (FileSaveInformation fileSaveInformation)
+ {
+ if (!string.IsNullOrEmpty (fileSaveInformation.FileName))
+ AutoSave.RemoveAutoSaveFile (fileSaveInformation.FileName);
+ textEditorImpl.Save (fileSaveInformation);
+ }
+
+ void IViewContent.Save (string fileName)
+ {
+ if (!string.IsNullOrEmpty (fileName))
+ AutoSave.RemoveAutoSaveFile (fileName);
+ textEditorImpl.Save (new FileSaveInformation (fileName));
+ }
+
+ void IViewContent.Save ()
+ {
+ if (!string.IsNullOrEmpty (textEditorImpl.ContentName))
+ AutoSave.RemoveAutoSaveFile (textEditorImpl.ContentName);
+ textEditorImpl.Save ();
+ }
+
+ void IViewContent.DiscardChanges ()
+ {
+ if (!string.IsNullOrEmpty (textEditorImpl.ContentName))
+ AutoSave.RemoveAutoSaveFile (textEditorImpl.ContentName);
+ textEditorImpl.DiscardChanges ();
+ }
+
+ public MonoDevelop.Projects.Project Project {
+ get {
+ return textEditorImpl.Project;
+ }
+ set {
+ textEditorImpl.Project = value;
+ UpdateTextEditorOptions (null, null);
+ }
+ }
+
+ string IViewContent.PathRelativeToProject {
+ get {
+ return textEditorImpl.PathRelativeToProject;
+ }
+ }
+
+ string IViewContent.ContentName {
+ get {
+ return textEditorImpl.ContentName;
+ }
+ set {
+ textEditorImpl.ContentName = value;
+ }
+ }
+
+ string IViewContent.UntitledName {
+ get {
+ return textEditorImpl.UntitledName;
+ }
+ set {
+ textEditorImpl.UntitledName = value;
+ }
+ }
+
+ string IViewContent.StockIconId {
+ get {
+ return textEditorImpl.StockIconId;
+ }
+ }
+
+ bool IViewContent.IsUntitled {
+ get {
+ return textEditorImpl.IsUntitled;
+ }
+ }
+
+ bool IViewContent.IsViewOnly {
+ get {
+ return textEditorImpl.IsViewOnly;
+ }
+ }
+
+ bool IViewContent.IsFile {
+ get {
+ return textEditorImpl.IsFile;
+ }
+ }
+
+ bool IViewContent.IsDirty {
+ get {
+ return textEditorImpl.IsDirty;
+ }
+ set {
+ textEditorImpl.IsDirty = value;
+ }
+ }
+
+ bool IViewContent.IsReadOnly {
+ get {
+ return textEditorImpl.IsReadOnly;
+ }
+ }
+
+ #endregion
+
+ #region IBaseViewContent implementation
+ object IBaseViewContent.GetContent (Type type)
+ {
+ if (type.IsAssignableFrom (typeof(TextEditor)))
+ return textEditor;
+ var ext = textEditorImpl.EditorExtension;
+ while (ext != null) {
+ if (type.IsInstanceOfType (ext))
+ return ext;
+ ext = ext.Next;
+ }
+ return textEditorImpl.GetContent (type);
+ }
+
+ public virtual IEnumerable<T> GetContents<T> () where T : class
+ {
+ if (typeof(T) == typeof(TextEditor)) {
+ yield return (T)(object)textEditor;
+ yield break;
+ }
+ var result = this 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;
+ }
+ foreach (var cnt in textEditorImpl.GetContents<T> ()) {
+ yield return cnt;
+ }
+ }
+
+ bool IBaseViewContent.CanReuseView (string fileName)
+ {
+ return textEditorImpl.CanReuseView (fileName);
+ }
+
+ void IBaseViewContent.RedrawContent ()
+ {
+ textEditorImpl.RedrawContent ();
+ }
+
+ IWorkbenchWindow IBaseViewContent.WorkbenchWindow {
+ get {
+ return textEditorImpl.WorkbenchWindow;
+ }
+ set {
+ textEditorImpl.WorkbenchWindow = value;
+ }
+ }
+
+ Gtk.Widget IBaseViewContent.Control {
+ get {
+ return textEditor;
+ }
+ }
+
+ string IBaseViewContent.TabPageLabel {
+ get {
+ return textEditorImpl.TabPageLabel;
+ }
+ }
+
+ #endregion
+
+ #region IDisposable implementation
+
+ void IDisposable.Dispose ()
+ {
+ DefaultSourceEditorOptions.Instance.Changed -= UpdateTextEditorOptions;
+ RemovePolicyChangeHandler ();
+ RemoveAutoSaveTimer ();
+ RemoveErrorUndelinesResetTimerId ();
+ textEditorImpl.Dispose ();
+ }
+
+ #endregion
+
+ #region ICommandRouter implementation
+
+ object ICommandRouter.GetNextCommandTarget ()
+ {
+ return textEditorImpl;
+ }
+
+ #endregion
+
+ #region Commands
+ void ToggleCodeCommentWithBlockComments ()
+ {
+ var blockStarts = TextEditorFactory.GetSyntaxProperties (textEditor.MimeType, "BlockCommentStart");
+ var blockEnds = TextEditorFactory.GetSyntaxProperties (textEditor.MimeType, "BlockCommentEnd");
+ if (blockStarts == null || blockEnds == null || blockStarts.Length == 0 || blockEnds.Length == 0)
+ return;
+
+ string blockStart = blockStarts[0];
+ string blockEnd = blockEnds[0];
+
+ using (var undo = textEditor.OpenUndoGroup ()) {
+ IDocumentLine startLine;
+ IDocumentLine endLine;
+
+ if (textEditor.IsSomethingSelected) {
+ startLine = textEditor.GetLineByOffset (textEditor.SelectionRange.Offset);
+ endLine = textEditor.GetLineByOffset (textEditor.SelectionRange.EndOffset);
+ } else {
+ startLine = endLine = textEditor.GetLine (textEditor.CaretLine);
+ }
+ string startLineText = textEditor.GetTextAt (startLine.Offset, startLine.Length);
+ string endLineText = textEditor.GetTextAt (endLine.Offset, endLine.Length);
+ if (startLineText.StartsWith (blockStart, StringComparison.Ordinal) && endLineText.EndsWith (blockEnd, StringComparison.Ordinal)) {
+ textEditor.RemoveText (endLine.Offset + endLine.Length - blockEnd.Length, blockEnd.Length);
+ textEditor.RemoveText (startLine.Offset, blockStart.Length);
+ if (textEditor.IsSomethingSelected) {
+ textEditor.SelectionAnchorOffset -= blockEnd.Length;
+ }
+ } else {
+ textEditor.InsertText (endLine.Offset + endLine.Length, blockEnd);
+ textEditor.InsertText (startLine.Offset, blockStart);
+ if (textEditor.IsSomethingSelected) {
+ textEditor.SelectionAnchorOffset += blockEnd.Length;
+ }
+ }
+ }
+ }
+
+ bool TryGetLineCommentTag (out string commentTag)
+ {
+ var lineComments = TextEditorFactory.GetSyntaxProperties (textEditor.MimeType, "LineComment");
+ if (lineComments == null || lineComments.Length == 0) {
+ commentTag = null;
+ return false;
+ }
+ commentTag = lineComments [0];
+ return true;
+ }
+
+ [CommandUpdateHandler (EditCommands.AddCodeComment)]
+ [CommandUpdateHandler (EditCommands.RemoveCodeComment)]
+ [CommandUpdateHandler (EditCommands.ToggleCodeComment)]
+ void OnUpdateToggleComment (CommandInfo info)
+ {
+ var lineComments = TextEditorFactory.GetSyntaxProperties (textEditor.MimeType, "LineComment");
+ if (lineComments != null && lineComments.Length > 0) {
+ info.Visible = true;
+ return;
+ }
+ var blockStarts = TextEditorFactory.GetSyntaxProperties (textEditor.MimeType, "BlockCommentStart");
+ var blockEnds = TextEditorFactory.GetSyntaxProperties (textEditor.MimeType, "BlockCommentEnd");
+ info.Visible = blockStarts != null && blockStarts.Length > 0 && blockEnds != null && blockEnds.Length > 0;
+ }
+
+ [CommandHandler (EditCommands.ToggleCodeComment)]
+ internal void ToggleCodeComment ()
+ {
+ string commentTag;
+ if (!TryGetLineCommentTag (out commentTag))
+ return;
+ bool comment = false;
+ foreach (var line in GetSelectedLines (textEditor)) {
+ int startOffset;
+ int offset = line.Offset;
+ if (!StartsWith (textEditor, offset, line.Length, commentTag, out startOffset)) {
+ if (startOffset - offset == line.Length) // case: line consists only of white spaces
+ continue;
+ comment = true;
+ break;
+ }
+ }
+
+ if (comment) {
+ AddCodeComment ();
+ } else {
+ RemoveCodeComment ();
+ }
+ }
+
+ static bool StartsWith (ITextSource text, int offset, int length, string commentTag, out int startOffset)
+ {
+ int max = Math.Min (offset + length, text.Length);
+ int i = offset;
+ for (; i < max; i++) {
+ char ch = text.GetCharAt (i);
+ if (ch != ' ' && ch != '\t')
+ break;
+ }
+ startOffset = i;
+ for (int j = 0; j < commentTag.Length; j++) {
+ if (text.GetCharAt (i) != commentTag [j])
+ return false;
+ i++;
+ }
+
+ return true;
+ }
+
+ static IEnumerable<IDocumentLine> GetSelectedLines (TextEditor textEditor)
+ {
+ var selection = textEditor.SelectionRange;
+ var line = textEditor.GetLineByOffset (selection.EndOffset);
+ do {
+ yield return line;
+ line = line.PreviousLine;
+ } while (line != null && line.EndOffset > selection.Offset);
+ }
+
+ [CommandHandler (EditCommands.AddCodeComment)]
+ internal void AddCodeComment ()
+ {
+ string commentTag;
+ if (!TryGetLineCommentTag (out commentTag))
+ return;
+
+ using (var undo = textEditor.OpenUndoGroup ()) {
+ var wasSelected = textEditor.IsSomethingSelected;
+ var lead = textEditor.SelectionLeadOffset;
+ var anchor = textEditor.SelectionAnchorOffset;
+ var lineAndIndents = new List<Tuple<IDocumentLine, string>>();
+ string indent = null;
+ var oldVersion = textEditor.Version;
+ foreach (var line in GetSelectedLines (textEditor)) {
+ var curIndent = line.GetIndentation (textEditor);
+ if (line.Length == curIndent.Length) {
+ lineAndIndents.Add (Tuple.Create ((IDocumentLine)null, ""));
+ continue;
+ }
+ if (indent == null || curIndent.Length < indent.Length)
+ indent = curIndent;
+ lineAndIndents.Add (Tuple.Create (line, curIndent));
+ }
+
+ foreach (var line in lineAndIndents) {
+ if (line.Item1 == null)
+ continue;
+ textEditor.InsertText (line.Item1.Offset + indent.Length, commentTag);
+ }
+ if (wasSelected) {
+ textEditor.SelectionAnchorOffset = oldVersion.MoveOffsetTo (textEditor.Version, anchor);
+ textEditor.SelectionLeadOffset = oldVersion.MoveOffsetTo (textEditor.Version, lead);
+ }
+ }
+ }
+
+ [CommandHandler (EditCommands.RemoveCodeComment)]
+ internal void RemoveCodeComment ()
+ {
+ string commentTag;
+ if (!TryGetLineCommentTag (out commentTag))
+ return;
+
+ using (var undo = textEditor.OpenUndoGroup ()) {
+ var wasSelected = textEditor.IsSomethingSelected;
+ var lead = textEditor.SelectionLeadOffset;
+ var anchor = textEditor.SelectionAnchorOffset;
+ int lines = 0;
+
+ IDocumentLine first = null;
+ IDocumentLine last = null;
+ var oldVersion = textEditor.Version;
+ foreach (var line in GetSelectedLines (textEditor)) {
+ int startOffset;
+ if (StartsWith (textEditor, line.Offset, line.Length, commentTag, out startOffset)) {
+ textEditor.RemoveText (startOffset, commentTag.Length);
+ lines++;
+ }
+
+ first = line;
+ if (last == null)
+ last = line;
+ }
+
+ if (wasSelected) {
+// if (IdeApp.Workbench != null)
+// CodeFormatterService.Format (textEditor, IdeApp.Workbench.ActiveDocument, TextSegment.FromBounds (first.Offset, last.EndOffset));
+
+ textEditor.SelectionAnchorOffset = oldVersion.MoveOffsetTo (textEditor.Version, anchor);
+ textEditor.SelectionLeadOffset = oldVersion.MoveOffsetTo (textEditor.Version, lead);
+ }
+ }
+ }
+
+ [CommandHandler (EditCommands.InsertGuid)]
+ void InsertGuid ()
+ {
+ textEditor.InsertAtCaret (Guid.NewGuid ().ToString ());
+ }
+
+ [CommandUpdateHandler (MessageBubbleCommands.Toggle)]
+ public void OnUpdateToggleErrorTextMarker (CommandInfo info)
+ {
+ var line = textEditor.GetLine (textEditor.CaretLine);
+ if (line == null) {
+ info.Visible = false;
+ return;
+ }
+
+ var marker = (IMessageBubbleLineMarker)textEditor.GetLineMarkers (line).FirstOrDefault (m => m is IMessageBubbleLineMarker);
+ info.Visible = marker != null;
+ }
+
+ [CommandHandler (MessageBubbleCommands.Toggle)]
+ public void OnToggleErrorTextMarker ()
+ {
+ var line = textEditor.GetLine (textEditor.CaretLine);
+ if (line == null)
+ return;
+ var marker = (IMessageBubbleLineMarker)textEditor.GetLineMarkers (line).FirstOrDefault (m => m is IMessageBubbleLineMarker);
+ if (marker != null) {
+ marker.IsVisible = !marker.IsVisible;
+ }
+ }
+ #endregion
+
+ #region IQuickTaskProvider implementation
+ List<QuickTask> tasks = new List<QuickTask> ();
+
+ public event EventHandler TasksUpdated;
+
+ protected virtual void OnTasksUpdated (EventArgs e)
+ {
+ EventHandler handler = this.TasksUpdated;
+ if (handler != null)
+ handler (this, e);
+ }
+
+ public IEnumerable<QuickTask> QuickTasks {
+ get {
+ return tasks;
+ }
+ }
+
+ async void UpdateQuickTasks (ParsedDocument doc, CancellationToken token)
+ {
+ var newTasks = new List<QuickTask> ();
+ if (doc != null) {
+ foreach (var cmt in await doc.GetTagCommentsAsync(token).ConfigureAwait (false)) {
+ var newTask = new QuickTask (cmt.Text, textEditor.LocationToOffset (cmt.Region.Begin.Line, cmt.Region.Begin.Column), DiagnosticSeverity.Info);
+ newTasks.Add (newTask);
+ }
+
+ foreach (var error in await doc.GetErrorsAsync(token).ConfigureAwait (false)) {
+ var newTask = new QuickTask (error.Message, textEditor.LocationToOffset (error.Region.Begin.Line, error.Region.Begin.Column), error.ErrorType == MonoDevelop.Ide.TypeSystem.ErrorType.Error ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning);
+ newTasks.Add (newTask);
+ }
+ }
+ Application.Invoke (delegate {
+ if (token.IsCancellationRequested)
+ return;
+ tasks = newTasks;
+ OnTasksUpdated (EventArgs.Empty);
+ });
+ }
+ #endregion
+
+ #region Key bindings
+
+ [CommandHandler (TextEditorCommands.LineEnd)]
+ void OnLineEnd ()
+ {
+ EditActions.MoveCaretToLineEnd (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.LineStart)]
+ void OnLineStart ()
+ {
+ EditActions.MoveCaretToLineStart (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DeleteLeftChar)]
+ void OnDeleteLeftChar ()
+ {
+ EditActions.Backspace (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DeleteRightChar)]
+ void OnDeleteRightChar ()
+ {
+ EditActions.Delete (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.CharLeft)]
+ void OnCharLeft ()
+ {
+ EditActions.MoveCaretLeft (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.CharRight)]
+ void OnCharRight ()
+ {
+ EditActions.MoveCaretRight (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.LineUp)]
+ void OnLineUp ()
+ {
+ EditActions.MoveCaretUp (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.LineDown)]
+ void OnLineDown ()
+ {
+ EditActions.MoveCaretDown (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DocumentStart)]
+ void OnDocumentStart ()
+ {
+ EditActions.MoveCaretToDocumentStart (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DocumentEnd)]
+ void OnDocumentEnd ()
+ {
+ EditActions.MoveCaretToDocumentEnd (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.PageUp)]
+ void OnPageUp ()
+ {
+ EditActions.PageUp (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.PageDown)]
+ void OnPageDown ()
+ {
+ EditActions.PageDown (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DeleteLine)]
+ void OnDeleteLine ()
+ {
+ EditActions.DeleteCurrentLine (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DeleteToLineEnd)]
+ void OnDeleteToLineEnd ()
+ {
+ EditActions.DeleteCurrentLineToEnd (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.ScrollLineUp)]
+ void OnScrollLineUp ()
+ {
+ EditActions.ScrollLineUp (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.ScrollLineDown)]
+ void OnScrollLineDown ()
+ {
+ EditActions.ScrollLineDown (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.ScrollPageUp)]
+ void OnScrollPageUp ()
+ {
+ EditActions.ScrollPageUp (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.ScrollPageDown)]
+ void OnScrollPageDown ()
+ {
+ EditActions.ScrollPageDown (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.GotoMatchingBrace)]
+ void OnGotoMatchingBrace ()
+ {
+ EditActions.GotoMatchingBrace (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveLeft)]
+ void OnSelectionMoveLeft ()
+ {
+ EditActions.SelectionMoveLeft (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveRight)]
+ void OnSelectionMoveRight ()
+ {
+ EditActions.SelectionMoveRight (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.MovePrevWord)]
+ void OnMovePrevWord ()
+ {
+ EditActions.MovePrevWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.MoveNextWord)]
+ void OnMoveNextWord ()
+ {
+ EditActions.MoveNextWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMovePrevWord)]
+ void OnSelectionMovePrevWord ()
+ {
+ EditActions.SelectionMovePrevWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveNextWord)]
+ void OnSelectionMoveNextWord ()
+ {
+ EditActions.SelectionMoveNextWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.MovePrevSubword)]
+ void OnMovePrevSubword ()
+ {
+ EditActions.MovePrevSubWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.MoveNextSubword)]
+ void OnMoveNextSubword ()
+ {
+ EditActions.MoveNextSubWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMovePrevSubword)]
+ void OnSelectionMovePrevSubword ()
+ {
+ EditActions.SelectionMovePrevSubWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveNextSubword)]
+ void OnSelectionMoveNextSubword ()
+ {
+ EditActions.SelectionMoveNextSubWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveUp)]
+ void OnSelectionMoveUp ()
+ {
+ EditActions.SelectionMoveUp (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveDown)]
+ void OnSelectionMoveDown ()
+ {
+ EditActions.SelectionMoveDown (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveHome)]
+ void OnSelectionMoveHome ()
+ {
+ EditActions.SelectionMoveLineStart (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveEnd)]
+ void OnSelectionMoveEnd ()
+ {
+ EditActions.SelectionMoveLineEnd (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveToDocumentStart)]
+ void OnSelectionMoveToDocumentStart ()
+ {
+ EditActions.SelectionMoveToDocumentStart (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.ExpandSelectionToLine)]
+ void OnExpandSelectionToLine ()
+ {
+ EditActions.ExpandSelectionToLine (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionMoveToDocumentEnd)]
+ void OnSelectionMoveToDocumentEnd ()
+ {
+ EditActions.SelectionMoveToDocumentEnd (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SwitchCaretMode)]
+ void OnSwitchCaretMode ()
+ {
+ EditActions.SwitchCaretMode (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.InsertTab)]
+ void OnInsertTab ()
+ {
+ EditActions.InsertTab (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.RemoveTab)]
+ void OnRemoveTab ()
+ {
+ EditActions.RemoveTab (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.InsertNewLine)]
+ void OnInsertNewLine ()
+ {
+ EditActions.InsertNewLine (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.InsertNewLineAtEnd)]
+ void OnInsertNewLineAtEnd ()
+ {
+ EditActions.InsertNewLineAtEnd (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.InsertNewLinePreserveCaretPosition)]
+ void OnInsertNewLinePreserveCaretPosition ()
+ {
+ EditActions.InsertNewLinePreserveCaretPosition (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.CompleteStatement)]
+ void OnCompleteStatement ()
+ {
+ var doc = IdeApp.Workbench.ActiveDocument;
+ var generator = CodeGenerator.CreateGenerator (doc);
+ if (generator != null) {
+ generator.CompleteStatement (doc);
+ }
+ }
+
+ [CommandHandler (TextEditorCommands.DeletePrevWord)]
+ void OnDeletePrevWord ()
+ {
+ EditActions.DeletePreviousWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DeleteNextWord)]
+ void OnDeleteNextWord ()
+ {
+ EditActions.DeleteNextWord (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DeletePrevSubword)]
+ void OnDeletePrevSubword ()
+ {
+ EditActions.DeletePreviousSubword (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DeleteNextSubword)]
+ void OnDeleteNextSubword ()
+ {
+ EditActions.DeleteNextSubword (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionPageDownAction)]
+ void OnSelectionPageDownAction ()
+ {
+ EditActions.SelectionPageDown (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.SelectionPageUpAction)]
+ void OnSelectionPageUpAction ()
+ {
+ EditActions.SelectionPageUp (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.PulseCaret)]
+ void OnPulseCaretCommand ()
+ {
+ EditActions.StartCaretPulseAnimation (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.TransposeCharacters)]
+ void TransposeCharacters ()
+ {
+ EditActions.TransposeCharacters (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.DuplicateLine)]
+ void DuplicateLine ()
+ {
+ EditActions.DuplicateCurrentLine (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.RecenterEditor)]
+ void RecenterEditor ()
+ {
+ EditActions.RecenterEditor (textEditor);
+ }
+
+ [CommandHandler (EditCommands.JoinWithNextLine)]
+ void JoinLines ()
+ {
+ EditActions.JoinLines (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.MoveBlockUp)]
+ void OnMoveBlockUp ()
+ {
+ EditActions.MoveBlockUp (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.MoveBlockDown)]
+ void OnMoveBlockDown ()
+ {
+ EditActions.MoveBlockDown (textEditor);
+ }
+
+ [CommandHandler (TextEditorCommands.ToggleBlockSelectionMode)]
+ void OnToggleBlockSelectionMode ()
+ {
+ EditActions.ToggleBlockSelectionMode (textEditor);
+ }
+
+ [CommandHandler (EditCommands.IndentSelection)]
+ void IndentSelection ()
+ {
+ EditActions.IndentSelection (textEditor);
+ }
+
+ [CommandHandler (EditCommands.UnIndentSelection)]
+ void UnIndentSelection ()
+ {
+ EditActions.UnIndentSelection (textEditor);
+ }
+
+
+ [CommandHandler (EditCommands.SortSelectedLines)]
+ void SortSelectedLines ()
+ {
+ EditActions.SortSelectedLines (textEditor);
+ }
+
+ [CommandUpdateHandler (EditCommands.SortSelectedLines)]
+ void UpdateSortSelectedLines (CommandInfo ci)
+ {
+ var region = textEditor.SelectionRegion;
+ ci.Enabled = region.BeginLine != region.EndLine;
+ }
+ #endregion
+
+ }
+} \ No newline at end of file