diff options
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui')
15 files changed, 486 insertions, 469 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/AbstractBaseViewContent.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/AbstractBaseViewContent.cs index 392f2e6744..8c441c2e52 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/AbstractBaseViewContent.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/AbstractBaseViewContent.cs @@ -69,6 +69,14 @@ namespace MonoDevelop.Ide.Gui return null; } + public virtual IEnumerable<T> GetContents<T> () where T : class + { + var t = this as T; + if (t != null) + yield return t; + } + + #endregion #region IDisposable Members diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/AbstractViewContent.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/AbstractViewContent.cs index 00eb11bfa8..620ca00313 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/AbstractViewContent.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/AbstractViewContent.cs @@ -100,8 +100,13 @@ namespace MonoDevelop.Ide.Gui OnBeforeSave (EventArgs.Empty); this.Save (contentName); } - - public virtual void Save (string fileName) + + public void Save (string fileName) + { + Save (new FileSaveInformation (fileName)); + } + + public virtual void Save (FileSaveInformation fileSaveInformation) { throw new NotImplementedException (); } @@ -110,7 +115,12 @@ namespace MonoDevelop.Ide.Gui { } - public abstract void Load (string fileName); + public abstract void Load (FileOpenInformation fileOpenInformation); + + public void Load (string fileName) + { + Load (new FileOpenInformation (fileName, null)); + } public virtual void LoadNew (System.IO.Stream content, string mimeType) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/CommonTextEditorOptions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/CommonTextEditorOptions.cs deleted file mode 100644 index e04a6f9d14..0000000000 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/CommonTextEditorOptions.cs +++ /dev/null @@ -1,90 +0,0 @@ -// -// CommonTextEditorOptions.cs -// -// Author: -// Michael Hutchinson <mhutch@xamarin.com> -// -// Copyright (c) 2011 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; -using MonoDevelop.Ide.Fonts; - -namespace MonoDevelop.Ide.Gui -{ - /// <summary> - /// Text editor options that subscribe to MonoDevelop common settings. - /// </summary> - public class CommonTextEditorOptions : Mono.TextEditor.TextEditorOptions - { - bool disposed = false; - - public CommonTextEditorOptions () - { - PropertyService.PropertyChanged += PropertyServiceChanged; - base.FontName = PropertyService.Get ("FontName", FontService.MonospaceFontName); - base.ColorScheme = IdeApp.Preferences.ColorScheme; - FontService.RegisterFontChangedCallback ("Editor", UpdateFont); - } - - public override void Dispose () - { - if (disposed) - return; - disposed = true; - PropertyService.PropertyChanged -= PropertyServiceChanged; - FontService.RemoveCallback (UpdateFont); - } - - void UpdateFont () - { - base.FontName = FontName; - base.GutterFontName = GutterFontName; - this.OnChanged (EventArgs.Empty); - } - - void PropertyServiceChanged (object sender, PropertyChangedEventArgs e) - { - switch (e.Key) { - case "ColorScheme": { - string val = (string) e.NewValue; - if (string.IsNullOrEmpty (val)) - val = "Default"; - base.ColorScheme = val; - break; - } - } - } - - public override string ColorScheme { - set { throw new InvalidOperationException ("Set via global source editor options"); } - } - - public override string FontName { - get { - return FontService.FilterFontName (FontService.GetUnderlyingFontName ("Editor")); - } - set { - throw new InvalidOperationException ("Set via global source editor options"); - } - } - } -}
\ No newline at end of file diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs index bc7bf6f75c..f52c5526e9 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DefaultWorkbench.cs @@ -25,7 +25,6 @@ using System; using System.IO; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Drawing; using System.Diagnostics; @@ -39,12 +38,10 @@ using MonoDevelop.Ide.Codons; using MonoDevelop.Components.Commands; using MonoDevelop.Components.Docking; -using GLib; using MonoDevelop.Components.DockToolbars; using Gtk; using MonoDevelop.Components; using MonoDevelop.Ide.Extensions; -using Mono.TextEditor; using MonoDevelop.Components.MainToolbar; using MonoDevelop.Components.DockNotebook; @@ -368,7 +365,7 @@ namespace MonoDevelop.Ide.Gui return mimeimage; } - public virtual void ShowView (IViewContent content, bool bringToFront, DockNotebook notebook = null) + public virtual void ShowView (IViewContent content, bool bringToFront, IViewDisplayBinding binding = null, DockNotebook notebook = null) { bool isFile = content.IsFile; if (!isFile) { @@ -404,6 +401,10 @@ namespace MonoDevelop.Ide.Gui sdiWorkspaceWindow.TitleChanged += delegate { SetWorkbenchTitle (); }; sdiWorkspaceWindow.Closed += CloseWindowEvent; sdiWorkspaceWindow.Show (); + if (binding != null) + DisplayBindingService.AttachSubWindows (sdiWorkspaceWindow, binding); + + sdiWorkspaceWindow.CreateCommandHandler (); tab.Content = sdiWorkspaceWindow; if (mimeimage != null) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs index eff3218cc9..c96d9fb360 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Document.cs @@ -47,23 +47,25 @@ using MonoDevelop.Ide.Extensions; using System.Linq; using System.Threading; using MonoDevelop.Ide.TypeSystem; -using ICSharpCode.NRefactory; -using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.TypeSystem.Implementation; using System.Text; using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using MonoDevelop.Ide.Editor; +using MonoDevelop.Ide.Editor.Highlighting; +using MonoDevelop.Core.Text; namespace MonoDevelop.Ide.Gui { - public class Document : ICSharpCode.NRefactory.AbstractAnnotatable + + public class Document : DocumentContext { internal object MemoryProbe = Counters.DocumentsInMemory.CreateMemoryProbe (); IWorkbenchWindow window; - TextEditorExtension editorExtension; ParsedDocument parsedDocument; - IProjectContent singleFileContext; - Mono.TextEditor.ITextEditorDataProvider provider = null; + FilePath analysisDocumentFileName; + Microsoft.CodeAnalysis.DocumentId analysisDocument; const int ParseDelay = 600; @@ -75,12 +77,20 @@ namespace MonoDevelop.Ide.Gui get; set; } - - public TextEditorExtension EditorExtension { - get { return this.editorExtension; } + + /// <summary> + /// Returns the roslyn document for this document. This may return <c>null</c> if it's no compileable document. + /// Even if it's a C# file. + /// </summary> + public override Microsoft.CodeAnalysis.Document AnalysisDocument { + get { + if (analysisDocument == null) + return null; + return TypeSystemService.GetCodeAnalysisDocument (analysisDocument); + } } - public T GetContent<T> () where T : class + public override T GetContent<T> () { if (window == null) return null; @@ -97,39 +107,30 @@ namespace MonoDevelop.Ide.Gui return ret; } - //no, so look through the TexteditorExtensions as well - TextEditorExtension nextExtension = editorExtension; - while (nextExtension != null) { - if (typeof(T).IsAssignableFrom (nextExtension.GetType ())) - return nextExtension as T; - nextExtension = nextExtension.Next as TextEditorExtension; + //If we didn't find in ActiveView or ViewContent... Try in SubViews + foreach (var subView in window.SubViewContents) { + foreach (var cnt in subView.GetContents<T> ()) { + return cnt; + } } + return null; } - public IEnumerable<T> GetContents<T> () where T : class + public override IEnumerable<T> GetContents<T> () { - //check whether the ViewContent can return the type directly - T ret = (T) Window.ActiveViewContent.GetContent (typeof(T)); - if (ret != null) - yield return ret; - - //check the primary viewcontent - //not sure if this is the right thing to do, but things depend on this behaviour - if (Window.ViewContent != Window.ActiveViewContent) { - ret = (T) Window.ViewContent.GetContent (typeof(T)); - if (ret != null) - yield return ret; + foreach (var cnt in window.ViewContent.GetContents<T> ()) { + yield return cnt; } - - //no, so look through the TexteditorExtensions as well - TextEditorExtension nextExtension = editorExtension; - while (nextExtension != null) { - if (typeof(T).IsAssignableFrom (nextExtension.GetType ())) - yield return nextExtension as T; - nextExtension = nextExtension.Next as TextEditorExtension; + + foreach (var subView in window.SubViewContents) { + foreach (var cnt in subView.GetContents<T> ()) { + yield return cnt; + } } } + + static Document () { if (IdeApp.Workbench != null) { @@ -155,6 +156,19 @@ namespace MonoDevelop.Ide.Gui if (window.ViewContent.Project != null) window.ViewContent.Project.Modified += HandleProjectModified; window.ViewsChanged += HandleViewsChanged; + window.ViewContent.ContentNameChanged += delegate { + analysisDocument = null; + }; + MonoDevelopWorkspace.LoadingFinished += TypeSystemService_WorkspaceItemLoaded; + } + + void TypeSystemService_WorkspaceItemLoaded (object sender, EventArgs e) + { + if (adhocProject == null) + analysisDocument = null; + EnsureAnalysisDocumentIsOpen (); + if (analysisDocument != null) + StartReparseThread (); } /* void UpdateRegisteredDom (object sender, ProjectDomEventArgs e) @@ -182,13 +196,12 @@ namespace MonoDevelop.Ide.Gui get { return !Window.ViewContent.IsViewOnly && (Window.ViewContent.ContentName == null || Window.ViewContent.IsDirty); } set { Window.ViewContent.IsDirty = value; } } - - public bool HasProject { - get { return Window != null ? Window.ViewContent.Project != null : false; } - } - - public Project Project { - get { return Window != null ? Window.ViewContent.Project : null; } + + FilePath adHocFile; + Project adhocProject; + + public override Project Project { + get { return (Window != null ? Window.ViewContent.Project : null); } /* set { Window.ViewContent.Project = value; if (value != null) @@ -199,7 +212,7 @@ namespace MonoDevelop.Ide.Gui }*/ } - public bool IsCompileableInProject { + public override bool IsCompileableInProject { get { var project = Project; if (project == null) @@ -220,19 +233,15 @@ namespace MonoDevelop.Ide.Gui } } - public IProjectContent ProjectContent { - get { - return Project != null ? TypeSystemService.GetProjectContext (Project) : GetProjectContext (); - } - } - - public virtual ICompilation Compilation { - get { - return Project != null ? TypeSystemService.GetCompilation (Project) : GetProjectContext ().CreateCompilation (); - } + public Task<Microsoft.CodeAnalysis.Compilation> GetCompilationAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var project = TypeSystemService.GetCodeAnalysisProject (Project ?? adhocProject); + if (project == null) + return new Task<Microsoft.CodeAnalysis.Compilation> (() => null); + return project.GetCompilationAsync (cancellationToken); } - - public virtual ParsedDocument ParsedDocument { + + public override ParsedDocument ParsedDocument { get { return parsedDocument; } @@ -300,21 +309,16 @@ namespace MonoDevelop.Ide.Gui return new DocumentView (this, content); } - public string Name { + public override string Name { get { IViewContent view = Window.ViewContent; return view.IsUntitled ? view.UntitledName : view.ContentName; } } - public Mono.TextEditor.TextEditorData Editor { + public TextEditor Editor { get { - if (provider == null) { - provider = GetContent <Mono.TextEditor.ITextEditorDataProvider> (); - if (provider == null) - return null; - } - return provider.GetTextEditorData (); + return GetContent <TextEditor> (); } } @@ -378,21 +382,21 @@ namespace MonoDevelop.Ide.Gui // Set the file time of the current document after the file time of the written file, to prevent double file updates. // Note that the parsed document may be overwritten by a background thread to a more recent one. var doc = parsedDocument; - if (doc != null && doc.ParsedFile != null) { + if (doc != null) { string fileName = Window.ViewContent.ContentName; try { // filename could be null if the user cancelled SaveAs and this is a new & unsaved file if (fileName != null) - doc.ParsedFile.LastWriteTime = File.GetLastWriteTimeUtc (fileName); + doc.LastWriteTimeUtc = File.GetLastWriteTimeUtc (fileName); } catch (Exception e) { - doc.ParsedFile.LastWriteTime = DateTime.UtcNow; + doc.LastWriteTimeUtc = DateTime.UtcNow; LoggingService.LogWarning ("Exception while getting the write time from " + fileName, e); } } TypeSystemService.TrackFileChanges = true; } } - + public void SaveAs () { SaveAs (null); @@ -406,11 +410,11 @@ namespace MonoDevelop.Ide.Gui Encoding encoding = null; - IEncodedTextContent tbuffer = GetContent <IEncodedTextContent> (); + var tbuffer = GetContent <ITextSource> (); if (tbuffer != null) { - encoding = tbuffer.SourceEncoding; + encoding = tbuffer.Encoding; if (encoding == null) - encoding = Encoding.Default; + encoding = Encoding.UTF8; } if (filename == null) { @@ -446,16 +450,13 @@ namespace MonoDevelop.Ide.Gui // save backup first if ((bool)PropertyService.Get ("SharpDevelop.CreateBackupCopy", false)) { if (tbuffer != null && encoding != null) - tbuffer.Save (filename + "~", encoding); + TextFileUtility.WriteText (filename + "~", tbuffer.Text, encoding, tbuffer.UseBOM); else - Window.ViewContent.Save (filename + "~"); + Window.ViewContent.Save (new FileSaveInformation (filename + "~", encoding)); } TypeSystemService.RemoveSkippedfile (FileName); // do actual save - if (tbuffer != null && encoding != null) - tbuffer.Save (filename, encoding); - else - Window.ViewContent.Save (filename); + Window.ViewContent.Save (new FileSaveInformation (filename + "~", encoding)); FileService.NotifyFileChanged (filename); DesktopService.RecentFiles.AddFile (filename, (Project)null); @@ -468,12 +469,11 @@ namespace MonoDevelop.Ide.Gui { return ((SdiWorkspaceWindow)Window).CloseWindow (false, true); } - - void OnSaved (EventArgs args) + + protected override void OnSaved (EventArgs e) { IdeApp.Workbench.SaveFileStatus (); - if (Saved != null) - Saved (this, args); + base.OnSaved (e); } public void CancelParseTimeout () @@ -518,8 +518,14 @@ namespace MonoDevelop.Ide.Gui internal void DisposeDocument () { - DetachExtensionChain (); - RemoveAnnotations (typeof(System.Object)); + if (analysisDocument != null) { + TypeSystemService.InformDocumentClose (analysisDocument, FileName); + analysisDocument = null; + } + UnloadAdhocProject (); + if (Editor != null) { + Editor.Dispose (); + } if (window is SdiWorkspaceWindow) ((SdiWorkspaceWindow)window).DetachFromPathedDocument (); window.Closed -= OnClosed; @@ -531,11 +537,12 @@ namespace MonoDevelop.Ide.Gui if (window.ViewContent.Project != null) window.ViewContent.Project.Modified -= HandleProjectModified; window.ViewsChanged += HandleViewsChanged; + TypeSystemService.Workspace.WorkspaceChanged -= HandleWorkspaceChanged; + MonoDevelopWorkspace.LoadingFinished -= TypeSystemService_WorkspaceItemLoaded; + window = null; parsedDocument = null; - singleFileContext = null; - provider = null; views = null; viewsRO = null; } @@ -587,84 +594,44 @@ namespace MonoDevelop.Ide.Gui void InitializeExtensionChain () { - DetachExtensionChain (); - var editor = GetContent<IExtensibleTextEditor> (); - - ExtensionNodeList extensions = window.ExtensionContext.GetExtensionNodes ("/MonoDevelop/Ide/TextEditorExtensions", typeof(TextEditorExtensionNode)); - editorExtension = null; - TextEditorExtension last = null; - var mimetypeChain = DesktopService.GetMimeTypeInheritanceChainForFile (FileName).ToArray (); - foreach (TextEditorExtensionNode extNode in extensions) { - if (!extNode.Supports (FileName, mimetypeChain)) - continue; - TextEditorExtension ext; - try { - ext = (TextEditorExtension)extNode.CreateInstance (); - } catch (Exception e) { - LoggingService.LogError ("Error while creating text editor extension :" + extNode.Id + "(" + extNode.Type +")", e); - continue; - } - if (ext.ExtendsEditor (this, editor)) { - if (last != null) { - ext.Next = last.Next; - last.Next = ext; - last = ext; - } else { - editorExtension = last = ext; - last.Next = editor.AttachExtension (editorExtension); - } - ext.Initialize (this); - } - } + Editor.InitializeExtensionChain (this); + if (window is SdiWorkspaceWindow) ((SdiWorkspaceWindow)window).AttachToPathedDocument (GetContent<MonoDevelop.Ide.Gui.Content.IPathedDocument> ()); - } - void DetachExtensionChain () - { - while (editorExtension != null) { - try { - editorExtension.Dispose (); - } catch (Exception ex) { - LoggingService.LogError ("Exception while disposing extension:" + editorExtension, ex); - } - editorExtension = editorExtension.Next as TextEditorExtension; - } - editorExtension = null; } - void InitializeEditor (IExtensibleTextEditor editor) + void InitializeEditor () { - Editor.Document.TextReplaced += (o, a) => { + Editor.TextChanged += (o, a) => { if (parsedDocument != null) parsedDocument.IsInvalid = true; - if (Editor.Document.IsInAtomicUndo) { + if (Editor.IsInAtomicUndo) { wasEdited = true; } else { StartReparseThread (); } }; - Editor.Document.BeginUndo += delegate { + Editor.BeginAtomicUndoOperation += delegate { wasEdited = false; }; - Editor.Document.EndUndo += delegate { + Editor.EndAtomicUndoOperation += delegate { if (wasEdited) StartReparseThread (); }; - Editor.Document.Undone += (o, a) => StartReparseThread (); - Editor.Document.Redone += (o, a) => StartReparseThread (); +// Editor.Undone += (o, a) => StartReparseThread (); +// Editor.Redone += (o, a) => StartReparseThread (); InitializeExtensionChain (); } internal void OnDocumentAttached () { - IExtensibleTextEditor editor = GetContent<IExtensibleTextEditor> (); - if (editor != null) { - InitializeEditor (editor); + if (Editor != null) { + InitializeEditor (); RunWhenLoaded (delegate { ListenToProjectLoad (Project); }); } @@ -680,24 +647,25 @@ namespace MonoDevelop.Ide.Gui public void RunWhenLoaded (System.Action action) { var e = Editor; - if (e == null || e.Document == null) { + if (e == null) { action (); return; } - e.Document.RunWhenLoaded (action); + e.RunWhenLoaded (action); } - public void AttachToProject (Project project) + public override void AttachToProject (Project project) { SetProject (project); } - TypeSystemService.ProjectContentWrapper currentWrapper; internal void SetProject (Project project) { if (Window == null || Window.ViewContent == null || Window.ViewContent.Project == project) return; - DetachExtensionChain (); + UnloadAdhocProject (); + if (adhocProject == null) + analysisDocument = null; ISupportsProjectReload pr = GetContent<ISupportsProjectReload> (); if (pr != null) { // Unsubscribe project events @@ -709,22 +677,19 @@ namespace MonoDevelop.Ide.Gui if (project != null) project.Modified += HandleProjectModified; InitializeExtensionChain (); - + TypeSystemService.Workspace.WorkspaceChanged += HandleWorkspaceChanged; ListenToProjectLoad (project); } - void ListenToProjectLoad (Project project) + void HandleWorkspaceChanged (object sender, Microsoft.CodeAnalysis.WorkspaceChangeEventArgs e) { - if (currentWrapper != null) { - currentWrapper.Loaded -= HandleInLoadChanged; - currentWrapper = null; - } - if (project != null) { - var wrapper = TypeSystemService.GetProjectContentWrapper (project); - wrapper.Loaded += HandleInLoadChanged; - currentWrapper = wrapper; - currentWrapper.RequestLoad (); + if (e.Kind == Microsoft.CodeAnalysis.WorkspaceChangeKind.DocumentChanged && e.DocumentId == analysisDocument) { + OnDocumentParsed (EventArgs.Empty); } + } + + void ListenToProjectLoad (Project project) + { StartReparseThread (); } @@ -746,18 +711,30 @@ namespace MonoDevelop.Ide.Gui /// <returns> /// A <see cref="ParsedDocument"/> that contains the current dom. /// </returns> - public ParsedDocument UpdateParseDocument () + public override ParsedDocument UpdateParseDocument () { try { + EnsureAnalysisDocumentIsOpen (); string currentParseFile = FileName; var editor = Editor; if (editor == null || string.IsNullOrEmpty (currentParseFile)) return null; TypeSystemService.AddSkippedFile (currentParseFile); - string currentParseText = editor.Text; - this.parsedDocument = TypeSystemService.ParseFile (Project, currentParseFile, editor.Document.MimeType, currentParseText); - if (Project == null && this.parsedDocument != null) { - singleFileContext = GetProjectContext ().AddOrUpdateFiles (parsedDocument.ParsedFile); + var currentParseText = editor.CreateDocumentSnapshot (); + CancelOldParsing(); + var project = Project ?? adhocProject; + if (project != null && TypeSystemService.CanParseProjections (project, Editor.MimeType, FileName)) { + var task = TypeSystemService.ParseProjection (project, currentParseFile, editor.MimeType, currentParseText); + if (task.Result != null) { + var p = task.Result; + this.parsedDocument = p.ParsedDocument; + var projections = p.Projections; + foreach (var p2 in projections) + p2.CreateProjectedEditor (this); + Editor.SetOrUpdateProjections (this, projections, p.DisabledProjectionFeatures); + } + } else { + this.parsedDocument = TypeSystemService.ParseFile (project, currentParseFile, editor.MimeType, currentParseText).Result ?? this.parsedDocument; } } finally { @@ -765,89 +742,136 @@ namespace MonoDevelop.Ide.Gui } return this.parsedDocument; } + + uint parseTimeout = 0; - static readonly Lazy<IUnresolvedAssembly> mscorlib = new Lazy<IUnresolvedAssembly> ( () => new IkvmLoader ().LoadAssemblyFile (typeof (object).Assembly.Location)); - static readonly Lazy<IUnresolvedAssembly> systemCore = new Lazy<IUnresolvedAssembly>( () => new IkvmLoader ().LoadAssemblyFile (typeof (System.Linq.Enumerable).Assembly.Location)); - static readonly Lazy<IUnresolvedAssembly> system = new Lazy<IUnresolvedAssembly>( () => new IkvmLoader ().LoadAssemblyFile (typeof (System.Uri).Assembly.Location)); - - static IUnresolvedAssembly Mscorlib { get { return mscorlib.Value; } } - static IUnresolvedAssembly SystemCore { get { return systemCore.Value; } } - static IUnresolvedAssembly System { get { return system.Value; } } - - public bool IsProjectContextInUpdate { - get { - if (currentWrapper == null) - return false; - return !currentWrapper.IsLoaded; + void EnsureAnalysisDocumentIsOpen () + { + if (analysisDocument != null) + return; + if (Editor == null) { + analysisDocument = null; + return; + } + analysisDocumentFileName = FileName; + if (Project != null) { + RoslynWorkspace = TypeSystemService.GetWorkspace (this.Project.ParentSolution); + analysisDocument = TypeSystemService.GetDocumentId (this.Project, this.FileName); + if (analysisDocument != null) { + TypeSystemService.InformDocumentOpen (analysisDocument, Editor); + } + } else { + lock (adhocProjectLock) { + if (adhocProject != null) { + return; + } + if (Editor != null && Editor.MimeType == "text/x-csharp") { + var newProject = new DotNetAssemblyProject (Microsoft.CodeAnalysis.LanguageNames.CSharp); + this.adhocProject = newProject; + + newProject.Name = "InvisibleProject"; + newProject.References.Add (new ProjectReference (ReferenceType.Package, "mscorlib")); + newProject.References.Add (new ProjectReference (ReferenceType.Package, "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")); + newProject.References.Add (new ProjectReference (ReferenceType.Package, "System.Core")); + + newProject.FileName = "test.csproj"; + adHocFile = Platform.IsWindows ? "C:\\a.cs" : "/a.cs"; + newProject.Files.Add (new ProjectFile (adHocFile, BuildAction.Compile)); + + var solution = new Solution (); + solution.AddConfiguration ("", true); + solution.DefaultSolutionFolder.AddItem (newProject); + using (var monitor = new MonoDevelop.Core.ProgressMonitoring.NullProgressMonitor ()) + RoslynWorkspace = TypeSystemService.Load (solution, monitor, false); + analysisDocument = TypeSystemService.GetDocumentId (RoslynWorkspace, adhocProject, adHocFile); + TypeSystemService.InformDocumentOpen (RoslynWorkspace, analysisDocument, Editor); + } + } } } + object adhocProjectLock = new object(); - public virtual IProjectContent GetProjectContext () + void UnloadAdhocProject () { - if (Project == null) { - if (singleFileContext == null) { - singleFileContext = new ICSharpCode.NRefactory.CSharp.CSharpProjectContent (); - singleFileContext = singleFileContext.AddAssemblyReferences (new [] { Mscorlib, System, SystemCore }); - } - if (parsedDocument != null) - return singleFileContext.AddOrUpdateFiles (parsedDocument.ParsedFile); - return singleFileContext; + lock (adhocProjectLock) { + if (adhocProject == null) + return; + TypeSystemService.Unload (adhocProject.ParentSolution.ParentWorkspace); + adhocProject = null; } - - return TypeSystemService.GetProjectContext (Project); } - - uint parseTimeout = 0; + object reparseLock = new object(); - internal void StartReparseThread () + CancellationTokenSource parseTokenSource = new CancellationTokenSource(); + int reparseQueue; + void CancelOldParsing() { - lock (reparseLock) { - if (currentWrapper != null) - currentWrapper.EnsureReferencesAreLoaded (); + parseTokenSource.Cancel (); + parseTokenSource = new CancellationTokenSource (); + } + internal void StartReparseThread () + { + string currentParseFile = adhocProject != null ? adHocFile : FileName; + if (string.IsNullOrEmpty (currentParseFile)) + return; + Interlocked.Increment (ref reparseQueue); + Application.Invoke (delegate { + if (Interlocked.Decrement (ref reparseQueue) != 0) { + return; + } // Don't directly parse the document because doing it at every key press is // very inefficient. Do it after a small delay instead, so several changes can // be parsed at the same time. - string currentParseFile = FileName; - if (string.IsNullOrEmpty (currentParseFile)) - return; + EnsureAnalysisDocumentIsOpen (); CancelParseTimeout (); - if (IsProjectContextInUpdate) { - return; - } - parseTimeout = GLib.Timeout.Add (ParseDelay, delegate { - var editor = Editor; - if (editor == null || IsProjectContextInUpdate) { - parseTimeout = 0; - return false; - } - string currentParseText = editor.Text; - string mimeType = editor.Document.MimeType; - ThreadPool.QueueUserWorkItem (delegate { - if (IsProjectContextInUpdate) { - return; - } - TypeSystemService.AddSkippedFile (currentParseFile); - var currentParsedDocument = TypeSystemService.ParseFile (Project, currentParseFile, mimeType, currentParseText); - Application.Invoke (delegate { - // this may be called after the document has closed, in that case the OnDocumentParsed event shouldn't be invoked. - if (isClosed) + var currentParseText = Editor.CreateSnapshot (); + string mimeType = Editor.MimeType; + CancelOldParsing (); + var token = parseTokenSource.Token; + var project = Project ?? adhocProject; + ThreadPool.QueueUserWorkItem (delegate { + TypeSystemService.AddSkippedFile (currentParseFile); + if (project != null && TypeSystemService.CanParseProjections (project, mimeType, currentParseFile)) { + TypeSystemService.ParseProjection (project, currentParseFile, mimeType, currentParseText, token).ContinueWith (task => { + if (token.IsCancellationRequested) return; - this.parsedDocument = currentParsedDocument; - OnDocumentParsed (EventArgs.Empty); - }); - }); + Application.Invoke (delegate { + // this may be called after the document has closed, in that case the OnDocumentParsed event shouldn't be invoked. + var taskResult = task.Result; + if (isClosed || taskResult == null || token.IsCancellationRequested) + return; + this.parsedDocument = taskResult.ParsedDocument; + var projections = taskResult.Projections; + foreach (var p2 in projections) + p2.CreateProjectedEditor (this); + Editor.SetOrUpdateProjections (this, projections, taskResult.DisabledProjectionFeatures); + OnDocumentParsed (EventArgs.Empty); + }); + }, TaskContinuationOptions.OnlyOnRanToCompletion); + } else { + TypeSystemService.ParseFile (project, currentParseFile, mimeType, currentParseText, token).ContinueWith (task => { + if (token.IsCancellationRequested) + return; + Application.Invoke (delegate { + // this may be called after the document has closed, in that case the OnDocumentParsed event shouldn't be invoked. + if (isClosed || task.Result == null || token.IsCancellationRequested) + return; + this.parsedDocument = task.Result; + OnDocumentParsed (EventArgs.Empty); + }); + }, TaskContinuationOptions.OnlyOnRanToCompletion); + } parseTimeout = 0; - return false; }); - } + }); } /// <summary> /// This method kicks off an async document parser and should be used instead of /// <see cref="UpdateParseDocument"/> unless you need the parsed document immediately. /// </summary> - public void ReparseDocument () + public override void ReparseDocument () { StartReparseThread (); } @@ -855,8 +879,8 @@ namespace MonoDevelop.Ide.Gui internal object ExtendedCommandTargetChain { get { // Only go through the text editor chain, if the text editor is selected as subview - if (Window != null && Window.ActiveViewContent.GetContent (typeof(IExtensibleTextEditor)) != null) - return editorExtension; + if (Window != null && Window.ActiveViewContent.GetContent (typeof(TextEditor)) != null) + return Editor.CommandRouter; return null; } } @@ -867,19 +891,10 @@ namespace MonoDevelop.Ide.Gui window.ViewContent.Project = null; } - protected virtual void OnDocumentParsed (EventArgs e) - { - EventHandler handler = this.DocumentParsed; - if (handler != null) - handler (this, e); - } - public event EventHandler Closed; - public event EventHandler Saved; public event EventHandler ViewChanged; - public event EventHandler DocumentParsed; - + public string[] CommentTags { get { if (IsFile) @@ -893,30 +908,16 @@ namespace MonoDevelop.Ide.Gui { //Document doc = IdeApp.Workbench.ActiveDocument; string loadedMimeType = DesktopService.GetMimeTypeForUri (fileName); - - Mono.TextEditor.Highlighting.SyntaxMode mode = null; - foreach (string mt in DesktopService.GetMimeTypeInheritanceChain (loadedMimeType)) { - mode = Mono.TextEditor.Highlighting.SyntaxModeService.GetSyntaxMode (null, mt); - if (mode != null) - break; - } - - if (mode == null) - return null; - - List<string> ctags; - if (mode.Properties.TryGetValue ("LineComment", out ctags) && ctags.Count > 0) { - return new string [] { ctags [0] }; - } - List<string> tags = new List<string> (); - if (mode.Properties.TryGetValue ("BlockCommentStart", out ctags)) - tags.Add (ctags [0]); - if (mode.Properties.TryGetValue ("BlockCommentEnd", out ctags)) - tags.Add (ctags [0]); - if (tags.Count == 2) - return tags.ToArray (); - else - return null; + + var result = TextEditorFactory.GetSyntaxProperties (loadedMimeType, "LineComment"); + if (result != null) + return result; + + var start = TextEditorFactory.GetSyntaxProperties (loadedMimeType, "BlockCommentStart"); + var end = TextEditorFactory.GetSyntaxProperties (loadedMimeType, "BlockCommentEnd"); + if (start != null && end != null) + return new [] { start[0], end[0] }; + return null; } // public MonoDevelop.Projects.CodeGeneration.CodeGenerator CreateCodeGenerator () @@ -932,7 +933,29 @@ namespace MonoDevelop.Ide.Gui public void DisableAutoScroll () { if (IsFile) - Mono.TextEditor.Utils.FileSettingsStore.Remove (FileName); + FileSettingsStore.Remove (FileName); + } + + public override OptionSet GetOptionSet () + { + return TypeSystemService.Workspace.Options; + } + + internal override Task<IReadOnlyList<Editor.Projection.Projection>> GetPartialProjectionsAsync (CancellationToken cancellationToken = default(CancellationToken)) + { + var parser = TypeSystemService.GetParser (Editor.MimeType); + if (parser == null) + return null; + var projectFile = Project.GetProjectFile (Editor.FileName); + if (projectFile == null) + return null; + if (!parser.CanGenerateProjection (Editor.MimeType, projectFile.BuildAction, Project.SupportedLanguages)) + return null; + try { + return parser.GetPartialProjectionsAsync (this, Editor, parsedDocument, cancellationToken); + } catch (NotSupportedException) { + return null; + } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DocumentSwitcher.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DocumentSwitcher.cs index 46edebf535..82fa7c413f 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DocumentSwitcher.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DocumentSwitcher.cs @@ -34,7 +34,6 @@ using Gdk; using Gtk; using MonoDevelop.Ide.Gui; using MonoDevelop.Core; -using Mono.TextEditor; using MonoDevelop.Components; namespace MonoDevelop.Ide @@ -262,8 +261,8 @@ namespace MonoDevelop.Ide { Gdk.Key key; Gdk.ModifierType mod; - Mono.TextEditor.KeyboardShortcut[] accels; - Mono.TextEditor.GtkWorkarounds.MapKeys (evnt, out key, out mod, out accels); + KeyboardShortcut[] accels; + GtkWorkarounds.MapKeys (evnt, out key, out mod, out accels); switch (accels [0].Key) { case Gdk.Key.Left: diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DocumentToolbar.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DocumentToolbar.cs index 1a2536782a..5dfd8bdaf1 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DocumentToolbar.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/DocumentToolbar.cs @@ -26,8 +26,6 @@ using System; using Gtk; using MonoDevelop.Components; -using Mono.TextEditor; - namespace MonoDevelop.Ide.Gui { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/HiddenTextEditorViewContent.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/HiddenTextEditorViewContent.cs index b070b93358..cbd23e5ea3 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/HiddenTextEditorViewContent.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/HiddenTextEditorViewContent.cs @@ -27,13 +27,20 @@ using System; using MonoDevelop.Ide.Gui.Content; using MonoDevelop.Core; -using Mono.TextEditor; +using MonoDevelop.Ide.Editor; +using MonoDevelop.Core.Text; namespace MonoDevelop.Ide.Gui { - public class HiddenTextEditorViewContent : MonoDevelop.Ide.Gui.AbstractViewContent, IEditableTextBuffer, Mono.TextEditor.ITextEditorDataProvider + public class HiddenTextEditorViewContent : MonoDevelop.Ide.Gui.AbstractViewContent, IServiceProvider { - Mono.TextEditor.TextEditorData data; + readonly TextEditor editor; + + public TextEditor Editor { + get { + return editor; + } + } public override Gtk.Widget Control { get { @@ -43,12 +50,17 @@ namespace MonoDevelop.Ide.Gui public HiddenTextEditorViewContent () { - document = new Mono.TextEditor.TextDocument (); - data = new Mono.TextEditor.TextEditorData (document); + editor = TextEditorFactory.CreateNewEditor (); Name = ""; } - - public override void Load (string fileName) + + public HiddenTextEditorViewContent (TextEditor editor) + { + this.editor = editor; + Name = editor.FileName; + } + + public override void Load (FileOpenInformation fileOpenInformation) { } @@ -63,54 +75,53 @@ namespace MonoDevelop.Ide.Gui public int LineCount { get { - return document.LineCount; + return editor.LineCount; } } - Mono.TextEditor.TextDocument document; public string Text { get { - return document.Text; + return editor.Text; } set { - document.Text = value; + editor.Text = value; } } public int InsertText (int position, string text) { - document.Insert (position, text); + editor.InsertText (position, text); return text.Length; } public void DeleteText (int position, int length) { - document.Replace (position, length, ""); + editor.ReplaceText (position, length, ""); } public int Length { get { - return document.TextLength; + return editor.Length; } } public string GetText (int startPosition, int endPosition) { - return document.GetTextBetween (startPosition, endPosition); + return editor.GetTextBetween (startPosition, endPosition); } public char GetCharAt (int position) { - return document.GetCharAt (position); + return editor.GetCharAt (position); } public int GetPositionFromLineColumn (int line, int column) { - return document.LocationToOffset (line, column); + return editor.LocationToOffset (line, column); } public void GetLineColumnFromPosition (int position, out int line, out int column) { - Mono.TextEditor.DocumentLocation loc = document.OffsetToLocation (position); + var loc = editor.OffsetToLocation (position); line = loc.Line; column = loc.Column; } @@ -119,32 +130,32 @@ namespace MonoDevelop.Ide.Gui public int CursorPosition { get { - return data.Caret.Offset; + return editor.CaretOffset; } set { - data.Caret.Offset = value; + editor.CaretOffset = value; } } public int SelectionStartPosition { get { - if (!data.IsSomethingSelected) - return data.Caret.Offset; - return data.SelectionRange.Offset; + if (!editor.IsSomethingSelected) + return editor.CaretOffset; + return editor.SelectionRange.Offset; } } public int SelectionEndPosition { get { - if (!data.IsSomethingSelected) - return data.Caret.Offset; - return data.SelectionRange.EndOffset; + if (!editor.IsSomethingSelected) + return editor.CaretOffset; + return editor.SelectionRange.EndOffset; } } public void Select (int startPosition, int endPosition) { - data.SelectionRange = new TextSegment (startPosition, endPosition - startPosition); + editor.SelectionRange = new TextSegment (startPosition, endPosition - startPosition); } public void ShowPosition (int position) @@ -195,12 +206,18 @@ namespace MonoDevelop.Ide.Gui { return new DisposeStub (); } - - public Mono.TextEditor.TextEditorData GetTextEditorData () + + #region IServiceProvider implementation + + object IServiceProvider.GetService (Type serviceType) { - return data; + if (serviceType.IsInstanceOfType (editor)) + return editor; + return null; } + + #endregion + public event EventHandler CaretPositionSet; - public event EventHandler<TextChangedEventArgs> TextChanged; } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IBaseViewContent.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IBaseViewContent.cs index c40c6f8525..ad246af631 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IBaseViewContent.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IBaseViewContent.cs @@ -27,6 +27,7 @@ using System; using Gtk; +using System.Collections.Generic; namespace MonoDevelop.Ide.Gui { @@ -41,7 +42,8 @@ namespace MonoDevelop.Ide.Gui string TabPageLabel { get; } object GetContent (Type type); - + IEnumerable<T> GetContents<T> () where T : class; + bool CanReuseView (string fileName); void RedrawContent (); } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IViewContent.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IViewContent.cs index 2fbc0c618e..0c76d3cc02 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IViewContent.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/IViewContent.cs @@ -30,7 +30,7 @@ using MonoDevelop.Projects; namespace MonoDevelop.Ide.Gui { - public interface IViewContent : IBaseViewContent + public interface IViewContent : IBaseViewContent { Project Project { get; set; } @@ -45,9 +45,11 @@ namespace MonoDevelop.Ide.Gui bool IsDirty { get; set; } bool IsReadOnly { get; } - void Load (string fileName); + void Load (FileOpenInformation fileOpenInformation); + void Load (string fileName); void LoadNew (System.IO.Stream content, string mimeType); - void Save (string fileName); + void Save (FileSaveInformation fileSaveInformation); + void Save (string fileName); void Save (); /// <summary> diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs index c5468e9ee5..05aba59465 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/SdiWorkspaceWindow.cs @@ -121,7 +121,10 @@ namespace MonoDevelop.Ide.Gui Add (box); SetTitleEvent(null, null); + } + internal void CreateCommandHandler () + { commandHandler = new ViewCommandHandlers (this); } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Styles.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Styles.cs index 8705e7258f..23fa36eb7b 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Styles.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Styles.cs @@ -115,7 +115,7 @@ namespace MonoDevelop.Ide.Gui public static int ProgressBarInnerPadding { get { return (int)(4 * PixelScale); } } public static int ProgressBarOuterPadding { get { return (int)(4 * PixelScale); } } - static readonly double PixelScale = Mono.TextEditor.GtkWorkarounds.GetPixelScale (); + static readonly double PixelScale = GtkWorkarounds.GetPixelScale (); // Toolbar diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ViewCommandHandlers.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ViewCommandHandlers.cs index 46a5e9712c..da50ac8bc1 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ViewCommandHandlers.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/ViewCommandHandlers.cs @@ -35,6 +35,7 @@ using MonoDevelop.Core; using MonoDevelop.Ide.Gui.Content; using MonoDevelop.Components.Commands; using MonoDevelop.Ide.Commands; +using MonoDevelop.Ide.Editor; namespace MonoDevelop.Ide.Gui { @@ -240,33 +241,33 @@ namespace MonoDevelop.Ide.Gui [CommandHandler (EditCommands.UppercaseSelection)] public void OnUppercaseSelection () { - IEditableTextBuffer buffer = GetContent <IEditableTextBuffer> (); + var buffer = GetContent <TextEditor> (); if (buffer == null) return; string selectedText = buffer.SelectedText; if (string.IsNullOrEmpty (selectedText)) { - int pos = buffer.CursorPosition; - string ch = buffer.GetText (pos, pos + 1); + int pos = buffer.CaretOffset; + string ch = buffer.GetTextAt (pos, pos + 1); string upper = ch.ToUpper (); if (upper == ch) { - buffer.CursorPosition = pos + 1; + buffer.CaretOffset = pos + 1; return; } using (var undo = buffer.OpenUndoGroup ()) { - buffer.DeleteText (pos, 1); + buffer.RemoveText (pos, 1); buffer.InsertText (pos, upper); - buffer.CursorPosition = pos + 1; + buffer.CaretOffset = pos + 1; } } else { string newText = selectedText.ToUpper (); if (newText == selectedText) return; - int startPos = buffer.SelectionStartPosition; + int startPos = buffer.SelectionRange.Offset; using (var undo = buffer.OpenUndoGroup ()) { - buffer.DeleteText (startPos, selectedText.Length); + buffer.RemoveText (startPos, selectedText.Length); buffer.InsertText (startPos, newText); - buffer.Select (startPos, startPos + newText.Length); + buffer.SetSelection (startPos, startPos + newText.Length); } } } @@ -274,40 +275,40 @@ namespace MonoDevelop.Ide.Gui [CommandUpdateHandler (EditCommands.UppercaseSelection)] protected void OnUppercaseSelection (CommandInfo info) { - IEditableTextBuffer buffer = GetContent <IEditableTextBuffer> (); + var buffer = GetContent <TextEditor> (); info.Enabled = buffer != null; } [CommandHandler (EditCommands.LowercaseSelection)] public void OnLowercaseSelection () { - IEditableTextBuffer buffer = GetContent <IEditableTextBuffer> (); + var buffer = GetContent <TextEditor> (); if (buffer == null) return; string selectedText = buffer.SelectedText; if (string.IsNullOrEmpty (selectedText)) { - int pos = buffer.CursorPosition; - string ch = buffer.GetText (pos, pos + 1); + int pos = buffer.CaretOffset; + string ch = buffer.GetTextAt (pos, pos + 1); string lower = ch.ToLower (); if (lower == ch) { - buffer.CursorPosition = pos + 1; + buffer.CaretOffset = pos + 1; return; }; using (var undo = buffer.OpenUndoGroup ()) { - buffer.DeleteText (pos, 1); + buffer.RemoveText (pos, 1); buffer.InsertText (pos, lower); - buffer.CursorPosition = pos + 1; + buffer.CaretOffset = pos + 1; } } else { string newText = selectedText.ToLower (); if (newText == selectedText) return; - int startPos = buffer.SelectionStartPosition; + int startPos = buffer.SelectionRange.Offset; using (var undo = buffer.OpenUndoGroup ()) { - buffer.DeleteText (startPos, selectedText.Length); + buffer.RemoveText (startPos, selectedText.Length); buffer.InsertText (startPos, newText); - buffer.Select (startPos, startPos + newText.Length); + buffer.SetSelection (startPos, startPos + newText.Length); } } } @@ -315,7 +316,7 @@ namespace MonoDevelop.Ide.Gui [CommandUpdateHandler (EditCommands.LowercaseSelection)] protected void OnLowercaseSelection (CommandInfo info) { - IEditableTextBuffer buffer = GetContent <IEditableTextBuffer> (); + var buffer = GetContent <TextEditor> (); info.Enabled = buffer != null; } @@ -346,69 +347,68 @@ namespace MonoDevelop.Ide.Gui [CommandHandler (TextEditorCommands.LineEnd)] protected void OnLineEnd () { - Mono.TextEditor.CaretMoveActions.LineEnd (doc.Editor); + doc.Editor.EditorActionHost.MoveCaretToLineEnd (); } [CommandHandler (TextEditorCommands.LineStart)] protected void OnLineStart () { - Mono.TextEditor.CaretMoveActions.LineStart (doc.Editor); + doc.Editor.EditorActionHost.MoveCaretToLineStart (); } [CommandHandler (TextEditorCommands.DeleteLeftChar)] protected void OnDeleteLeftChar () { - Mono.TextEditor.CaretMoveActions.Left (doc.Editor); - Mono.TextEditor.DeleteActions.Delete (doc.Editor); + doc.Editor.EditorActionHost.Backspace (); } [CommandHandler (TextEditorCommands.DeleteRightChar)] protected void OnDeleteRightChar () { - Mono.TextEditor.DeleteActions.Delete (doc.Editor); + doc.Editor.EditorActionHost.Delete (); } [CommandHandler (TextEditorCommands.CharLeft)] protected void OnCharLeft () { - Mono.TextEditor.CaretMoveActions.Left (doc.Editor); + doc.Editor.EditorActionHost.MoveCaretLeft (); } [CommandHandler (TextEditorCommands.CharRight)] protected void OnCharRight () { - Mono.TextEditor.CaretMoveActions.Right (doc.Editor); + doc.Editor.EditorActionHost.MoveCaretRight (); } [CommandHandler (TextEditorCommands.LineUp)] protected void OnLineUp () { - Mono.TextEditor.CaretMoveActions.Up (doc.Editor); + doc.Editor.EditorActionHost.MoveCaretUp (); } [CommandHandler (TextEditorCommands.LineDown)] protected void OnLineDown () { - Mono.TextEditor.CaretMoveActions.Down (doc.Editor); + doc.Editor.EditorActionHost.MoveCaretDown (); } [CommandHandler (TextEditorCommands.DocumentStart)] protected void OnDocumentStart () { - Mono.TextEditor.CaretMoveActions.ToDocumentStart (doc.Editor); + doc.Editor.EditorActionHost.MoveCaretToDocumentStart (); } [CommandHandler (TextEditorCommands.DocumentEnd)] protected void OnDocumentEnd () { - Mono.TextEditor.CaretMoveActions.ToDocumentEnd (doc.Editor); + doc.Editor.EditorActionHost.MoveCaretToDocumentEnd (); } [CommandHandler (TextEditorCommands.DeleteLine)] protected void OnDeleteLine () { - var line = doc.Editor.Document.GetLine (doc.Editor.Caret.Line); - doc.Editor.Remove (line.Offset, line.LengthIncludingDelimiter); + var line = doc.Editor.GetLine (doc.Editor.CaretLocation.Line); + doc.Editor.RemoveText (line.Offset, line.LengthIncludingDelimiter); } struct RemoveInfo @@ -435,7 +435,7 @@ namespace MonoDevelop.Ide.Gui return ch == ' ' || ch == '\t' || ch == '\v'; } - public static RemoveInfo GetRemoveInfo (Mono.TextEditor.TextDocument document, ref int pos) + public static RemoveInfo GetRemoveInfo (TextEditor document, ref int pos) { int len = 0; while (pos > 0 && IsWhiteSpace (document.GetCharAt (pos))) { @@ -458,22 +458,22 @@ namespace MonoDevelop.Ide.Gui [CommandHandler (EditCommands.RemoveTrailingWhiteSpaces)] public void OnRemoveTrailingWhiteSpaces () { - Mono.TextEditor.TextEditorData data = doc.Editor; + var data = doc.Editor; if (data == null) return; System.Collections.Generic.List<RemoveInfo> removeList = new System.Collections.Generic.List<RemoveInfo> (); - int pos = data.Document.TextLength - 1; - RemoveInfo removeInfo = RemoveInfo.GetRemoveInfo (data.Document, ref pos); + int pos = data.Length - 1; + RemoveInfo removeInfo = RemoveInfo.GetRemoveInfo (data, ref pos); if (!removeInfo.IsEmpty) removeList.Add (removeInfo); while (pos >= 0) { - char ch = data.Document.GetCharAt (pos); + char ch = data.GetCharAt (pos); if (ch == '\n' || ch == '\r') { - if (RemoveInfo.IsWhiteSpace (data.Document.GetCharAt (pos - 1))) { + if (RemoveInfo.IsWhiteSpace (data.GetCharAt (pos - 1))) { --pos; - removeInfo = RemoveInfo.GetRemoveInfo (data.Document, ref pos); + removeInfo = RemoveInfo.GetRemoveInfo (data, ref pos); if (!removeInfo.IsEmpty) removeList.Add (removeInfo); } @@ -482,8 +482,7 @@ namespace MonoDevelop.Ide.Gui } using (var undo = data.OpenUndoGroup ()) { foreach (var info in removeList) { - data.Document.Remove (info.Position, info.Length); - data.Document.CommitLineUpdate (data.Document.OffsetToLineNumber (info.Position)); + data.RemoveText (info.Position, info.Length); } } } @@ -491,7 +490,7 @@ namespace MonoDevelop.Ide.Gui [CommandUpdateHandler (EditCommands.RemoveTrailingWhiteSpaces)] protected void OnRemoveTrailingWhiteSpaces (CommandInfo info) { - info.Enabled = GetContent <IEditableTextBuffer> () != null; + info.Enabled = GetContent <TextEditor> () != null; } #region Folding diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs index d53c7c1c9c..ff8260efa1 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/Workbench.cs @@ -51,6 +51,7 @@ using MonoDevelop.Ide.Navigation; using MonoDevelop.Components.Docking; using MonoDevelop.Components.DockNotebook; using System.Text; +using MonoDevelop.Ide.Editor; namespace MonoDevelop.Ide.Gui { @@ -441,6 +442,25 @@ namespace MonoDevelop.Ide.Gui return OpenDocument (openFileInfo); } + static void ScrollToRequestedCaretLocation (Document doc, FileOpenInformation info) + { + var ipos = doc.Editor; + if ((info.Line >= 1 || info.Offset >= 0) && ipos != null) { + doc.DisableAutoScroll (); + doc.RunWhenLoaded (() => { + var loc = new DocumentLocation (info.Line, info.Column >= 1 ? info.Column : 1); + if (info.Offset >= 0) { + loc = ipos.OffsetToLocation (info.Offset); + } + if (loc.IsEmpty) + return; + ipos.SetCaretLocation (loc, info.Options.HasFlag (OpenDocumentOptions.HighlightCaretLine)); + if (info.Options.HasFlag (OpenDocumentOptions.CenterCaretLine)) + ipos.CenterToCaret (); + }); + } + } + internal Document OpenDocument (FilePath fileName, Project project, int line, int column, OpenDocumentOptions options, Encoding Encoding, IViewDisplayBinding binding, DockNotebook dockNotebook) { var openFileInfo = new FileOpenInformation (fileName, project) { @@ -455,7 +475,6 @@ namespace MonoDevelop.Ide.Gui return OpenDocument (openFileInfo); } - public Document OpenDocument (FileOpenInformation info) { if (string.IsNullOrEmpty (info.FileName)) @@ -481,18 +500,7 @@ namespace MonoDevelop.Ide.Gui doc.SetProject (info.Project); } - IEditableTextBuffer ipos = (IEditableTextBuffer) vcFound.GetContent (typeof(IEditableTextBuffer)); - if (info.Line >= 1 && ipos != null) { - doc.DisableAutoScroll (); - doc.RunWhenLoaded (() => - ipos.SetCaretTo ( - info.Line, - info.Column >= 1 ? info.Column : 1, - info.Options.HasFlag (OpenDocumentOptions.HighlightCaretLine), - info.Options.HasFlag (OpenDocumentOptions.CenterCaretLine) - ) - ); - } + ScrollToRequestedCaretLocation (doc, info); if (info.Options.HasFlag (OpenDocumentOptions.BringToFront)) { doc.Select (); @@ -518,6 +526,9 @@ namespace MonoDevelop.Ide.Gui if (info.NewContent != null) { Counters.OpenDocumentTimer.Trace ("Wrapping document"); Document doc = WrapDocument (info.NewContent.WorkbenchWindow); + + ScrollToRequestedCaretLocation (doc, info); + if (doc != null && info.Options.HasFlag (OpenDocumentOptions.BringToFront)) { doc.RunWhenLoaded (() => { if (doc.Window != null) @@ -577,7 +588,7 @@ namespace MonoDevelop.Ide.Gui if (binding == null) throw new ApplicationException("Can't create display binding for mime type: " + mimeType); - IViewContent newContent = binding.CreateContent (null, mimeType, null); + IViewContent newContent = binding.CreateContent (defaultName, mimeType, null); using (content) { newContent.LoadNew (content, mimeType); } @@ -588,9 +599,8 @@ namespace MonoDevelop.Ide.Gui newContent.UntitledName = defaultName; newContent.IsDirty = true; - workbench.ShowView (newContent, true); - DisplayBindingService.AttachSubWindows (newContent.WorkbenchWindow, binding); - + workbench.ShowView (newContent, true, binding); + var document = WrapDocument (newContent.WorkbenchWindow); document.StartReparseThread (); return document; @@ -979,8 +989,8 @@ namespace MonoDevelop.Ide.Gui var dp = new DocumentUserPrefs (); dp.FileName = FileService.AbsoluteToRelativePath (args.Item.BaseDirectory, document.FileName); if (document.Editor != null) { - dp.Line = document.Editor.Caret.Line; - dp.Column = document.Editor.Caret.Column; + dp.Line = document.Editor.CaretLine; + dp.Column = document.Editor.CaretColumn; } return dp; } @@ -1161,6 +1171,7 @@ namespace MonoDevelop.Ide.Gui ThreadPool.QueueUserWorkItem (delegate { lock (fileStatusLock) { // DateTime t = DateTime.Now; + if (fileStatus == null) return; List<FilePath> modified = new List<FilePath> (fileStatus.Count); @@ -1257,7 +1268,30 @@ namespace MonoDevelop.Ide.Gui } } } - + + public class FileSaveInformation + { + FilePath fileName; + public FilePath FileName { + get { + return fileName; + } + set { + fileName = value.CanonicalPath; + if (fileName.IsNullOrEmpty) + LoggingService.LogError ("FileName == null\n" + Environment.StackTrace); + } + } + + public Encoding Encoding { get; set; } + + public FileSaveInformation (FilePath fileName, Encoding encoding = null) + { + this.FileName = fileName; + this.Encoding = encoding; + } + } + public class FileOpenInformation { FilePath fileName; @@ -1266,19 +1300,29 @@ namespace MonoDevelop.Ide.Gui return fileName; } set { - fileName = FileService.ResolveFullPath (value.CanonicalPath); + fileName = value.CanonicalPath.ResolveLinks (); if (fileName.IsNullOrEmpty) LoggingService.LogError ("FileName == null\n" + Environment.StackTrace); } } public OpenDocumentOptions Options { get; set; } + int offset = -1; + public int Offset { + get { + return offset; + } + set { + offset = value; + } + } public int Line { get; set; } public int Column { get; set; } public IViewDisplayBinding DisplayBinding { get; set; } public IViewContent NewContent { get; set; } public Encoding Encoding { get; set; } public Project Project { get; set; } + internal DockNotebook DockNotebook { get; set; } [Obsolete("Use FileOpenInformation (FilePath filePath, Project project, int line, int column, OpenDocumentOptions options)")] @@ -1291,7 +1335,7 @@ namespace MonoDevelop.Ide.Gui } - public FileOpenInformation (FilePath filePath, Project project) + public FileOpenInformation (FilePath filePath, Project project = null) { this.FileName = filePath; this.Project = project; @@ -1393,12 +1437,8 @@ namespace MonoDevelop.Ide.Gui Counters.OpenDocumentTimer.Trace ("Loading file"); - IEncodedTextContent etc = (IEncodedTextContent) newContent.GetContent (typeof(IEncodedTextContent)); try { - if (fileInfo.Encoding != null && etc != null) - etc.Load (fileName, fileInfo.Encoding); - else - newContent.Load (fileName); + newContent.Load (fileInfo); } catch (InvalidEncodingException iex) { monitor.ReportError (GettextCatalog.GetString ("The file '{0}' could not opened. {1}", fileName, iex.Message), null); return; @@ -1420,14 +1460,14 @@ namespace MonoDevelop.Ide.Gui Counters.OpenDocumentTimer.Trace ("Showing view"); - workbench.ShowView (newContent, fileInfo.Options.HasFlag (OpenDocumentOptions.BringToFront), fileInfo.DockNotebook); + workbench.ShowView (newContent, fileInfo.Options.HasFlag (OpenDocumentOptions.BringToFront), binding, fileInfo.DockNotebook); - DisplayBindingService.AttachSubWindows (newContent.WorkbenchWindow, binding); newContent.WorkbenchWindow.DocumentType = binding.Name; - IEditableTextBuffer ipos = (IEditableTextBuffer) newContent.GetContent (typeof(IEditableTextBuffer)); + + var ipos = (TextEditor) newContent.GetContent (typeof(TextEditor)); if (fileInfo.Line > 0 && ipos != null) { - Mono.TextEditor.Utils.FileSettingsStore.Remove (fileName); + FileSettingsStore.Remove (fileName); ipos.RunWhenLoaded (JumpToLine); } @@ -1436,8 +1476,12 @@ namespace MonoDevelop.Ide.Gui void JumpToLine () { - IEditableTextBuffer ipos = (IEditableTextBuffer) newContent.GetContent (typeof(IEditableTextBuffer)); - ipos.SetCaretTo (Math.Max(1, fileInfo.Line), Math.Max(1, fileInfo.Column), fileInfo.Options.HasFlag (OpenDocumentOptions.HighlightCaretLine)); + var ipos = (TextEditor) newContent.GetContent (typeof(TextEditor)); + var loc = new DocumentLocation (Math.Max(1, fileInfo.Line), Math.Max(1, fileInfo.Column)); + if (fileInfo.Offset >= 0) { + loc = ipos.OffsetToLocation (fileInfo.Offset); + } + ipos.SetCaretLocation (loc, fileInfo.Options.HasFlag (OpenDocumentOptions.HighlightCaretLine)); } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/WorkbenchWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/WorkbenchWindow.cs index 92ed672f84..06098c686c 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/WorkbenchWindow.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui/WorkbenchWindow.cs @@ -26,6 +26,7 @@ using System; using System.Collections.Generic; +using MonoDevelop.Components; namespace MonoDevelop.Ide.Gui { @@ -35,7 +36,7 @@ namespace MonoDevelop.Ide.Gui public WorkbenchWindow (): base (Gtk.WindowType.Toplevel) { - Mono.TextEditor.GtkWorkarounds.FixContainerLeak (this); + GtkWorkarounds.FixContainerLeak (this); this.Role = "workbench"; } |