// // RazorCSharpCompletionBuilder.cs // // Author: // Piotr Dowgiallo // // Copyright (c) 2012 Piotr Dowgiallo // // 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.CSharp.Completion; using MonoDevelop.Ide.CodeCompletion; using Mono.TextEditor; using MonoDevelop.Ide.Gui; using MonoDevelop.AspNet.Razor; namespace MonoDevelop.CSharp.Completion { // Based on AspLanguageBuilder class RazorCSharpCompletionBuilder : IRazorCompletionBuilder { public bool SupportsLanguage (string language) { return language == "C#"; } CSharpCompletionTextEditorExtension CreateCompletion (Document realDocument, UnderlyingDocumentInfo docInfo, out CodeCompletionContext codeCompletionContext) { var documentLocation = docInfo.UnderlyingDocument.Editor.OffsetToLocation (docInfo.CaretPosition); codeCompletionContext = new CodeCompletionContext () { TriggerOffset = docInfo.CaretPosition, TriggerLine = documentLocation.Line, TriggerLineOffset = documentLocation.Column - 1 }; return new CSharpCompletionTextEditorExtension (docInfo.UnderlyingDocument) { CompletionWidget = CreateCompletionWidget (realDocument, docInfo) }; } CSharpCompletionTextEditorExtension CreateCompletionAndUpdate (Document realDocument, UnderlyingDocumentInfo docInfo, out CodeCompletionContext codeCompletionContext) { var completion = CreateCompletion (realDocument, docInfo, out codeCompletionContext); completion.UpdateParsedDocument (); return completion; } public ICompletionWidget CreateCompletionWidget (Document realDocument, UnderlyingDocumentInfo docInfo) { return new RazorCompletionWidget (realDocument, docInfo); } public ICompletionDataList HandlePopupCompletion (Document realDocument, UnderlyingDocumentInfo docInfo) { CodeCompletionContext ccc; var completion = CreateCompletionAndUpdate (realDocument, docInfo, out ccc); return completion.CodeCompletionCommand (ccc); } public ICompletionDataList HandleCompletion (Document realDocument, CodeCompletionContext completionContext, UnderlyingDocumentInfo docInfo, char currentChar, ref int triggerWordLength) { CodeCompletionContext ccc; var completion = CreateCompletionAndUpdate (realDocument, docInfo, out ccc); return completion.HandleCodeCompletion (completionContext, currentChar, ref triggerWordLength); } public ParameterDataProvider HandleParameterCompletion (Document realDocument, CodeCompletionContext completionContext, UnderlyingDocumentInfo docInfo, char completionChar) { CodeCompletionContext ccc; var completion = CreateCompletionAndUpdate (realDocument, docInfo, out ccc); return completion.HandleParameterCompletion (completionContext, completionChar); } public bool GetParameterCompletionCommandOffset (Document realDocument, UnderlyingDocumentInfo docInfo, out int cpos) { CodeCompletionContext ccc; var completion = CreateCompletionAndUpdate (realDocument, docInfo, out ccc); return completion.GetParameterCompletionCommandOffset (out cpos); } public int GetCurrentParameterIndex (Document realDocument, UnderlyingDocumentInfo docInfo, int startOffset) { CodeCompletionContext ccc; var completion = CreateCompletionAndUpdate (realDocument, docInfo, out ccc); return completion.GetCurrentParameterIndex (startOffset); } } class RazorCompletionWidget : ICompletionWidget { Document realDocument; UnderlyingDocumentInfo docInfo; public RazorCompletionWidget (Document realDocument, UnderlyingDocumentInfo docInfo) { this.realDocument = realDocument; this.docInfo = docInfo; } #region ICompletionWidget implementation public CodeCompletionContext CurrentCodeCompletionContext { get { return CreateCodeCompletionContext (CaretOffset); } } public event EventHandler CompletionContextChanged; public string GetText (int startOffset, int endOffset) { endOffset = Math.Min (endOffset, TextLength); if (endOffset <= startOffset) return String.Empty; return docInfo.UnderlyingDocument.Editor.GetTextAt (startOffset, endOffset - startOffset); } public char GetChar (int offset) { if (offset < 0 || offset >= TextLength) return '\0'; return docInfo.UnderlyingDocument.Editor.GetCharAt (offset); } public void Replace (int offset, int count, string text) { if (count > 0) docInfo.UnderlyingDocument.Editor.Text = docInfo.UnderlyingDocument.Editor.Text.Remove (offset, count); if (!string.IsNullOrEmpty (text)) docInfo.UnderlyingDocument.Editor.Text = docInfo.UnderlyingDocument.Editor.Text.Insert (offset, text); } public CodeCompletionContext CreateCodeCompletionContext (int triggerOffset) { var savedCtx = realDocument.GetContent ().CreateCodeCompletionContext ( realDocument.Editor.Caret.Offset + triggerOffset - docInfo.CaretPosition); var result = new CodeCompletionContext (); result.TriggerOffset = triggerOffset; var loc = docInfo.UnderlyingDocument.Editor.Document.OffsetToLocation (triggerOffset); result.TriggerLine = loc.Line; result.TriggerLineOffset = loc.Column - 1; result.TriggerXCoord = savedCtx.TriggerXCoord; result.TriggerYCoord = savedCtx.TriggerYCoord; result.TriggerTextHeight = savedCtx.TriggerTextHeight; return result; } public string GetCompletionText (CodeCompletionContext ctx) { if (ctx == null) return null; int min = Math.Min (ctx.TriggerOffset, CaretOffset); int max = Math.Max (ctx.TriggerOffset, CaretOffset); return docInfo.UnderlyingDocument.Editor.Document.GetTextBetween (min, max); } public void SetCompletionText (CodeCompletionContext ctx, string partial_word, string complete_word) { SetCompletionText (ctx, partial_word, complete_word, complete_word.Length); } public void SetCompletionText (CodeCompletionContext ctx, string partial_word, string complete_word, int wordOffset) { int offset = docInfo.OriginalCaretPosition + ctx.TriggerOffset - docInfo.CaretPosition; if (offset < 0 || offset > TextLength) return; var translatedCtx = new CodeCompletionContext (); translatedCtx.TriggerOffset = offset; var loc = docInfo.UnderlyingDocument.Editor.Document.OffsetToLocation (offset); translatedCtx.TriggerLine = loc.Line; translatedCtx.TriggerLineOffset = loc.Column - 1; translatedCtx.TriggerWordLength = ctx.TriggerWordLength; realDocument.GetContent ().SetCompletionText ( translatedCtx, partial_word, complete_word, wordOffset); } public int CaretOffset { get { return docInfo.UnderlyingDocument.Editor.Caret.Offset; } } public int TextLength { get { return docInfo.UnderlyingDocument.Editor.Document.TextLength; } } public int SelectedLength { get { return 0; } } public Gtk.Style GtkStyle { get { return Gtk.Widget.DefaultStyle; } } #endregion } }