public override void CorrectIndenting (PolicyContainer policyParent, IEnumerable<string> mimeTypeChain, TextEditorData data, int line) { LineSegment lineSegment = data.Document.GetLine (line); if (lineSegment == null) return; var policy = policyParent.Get<CFormattingPolicy> (mimeTypeChain); var tracker = new DocumentStateTracker<CIndentEngine> (new CIndentEngine (policy), data); tracker.UpdateEngine (lineSegment.Offset); for (int i = lineSegment.Offset; i < lineSegment.Offset + lineSegment.EditableLength; i++) { tracker.Engine.Push (data.Document.GetCharAt (i)); } string curIndent = lineSegment.GetIndentation (data.Document); int nlwsp = curIndent.Length; if (!tracker.Engine.LineBeganInsideMultiLineComment || (nlwsp < lineSegment.Length && data.Document.GetCharAt (lineSegment.Offset + nlwsp) == '*')) { // Possibly replace the indent string newIndent = tracker.Engine.ThisLineIndent; if (newIndent != curIndent) data.Replace (lineSegment.Offset, nlwsp, newIndent); } tracker.Dispose (); }
public override Task <ICompletionDataList> HandleCodeCompletionAsync(CodeCompletionContext completionContext, CompletionTriggerInfo triggerInfo, CancellationToken token = default(CancellationToken)) { if (triggerInfo.CompletionTriggerReason == CompletionTriggerReason.CharTyped) { int pos = completionContext.TriggerOffset; char ch = CompletionWidget != null?CompletionWidget.GetChar(pos - 1) : Editor.GetCharAt(pos - 1); if (pos > 0 && ch == triggerInfo.TriggerCharacter.Value) { tracker.UpdateEngine(); return(HandleCodeCompletion(completionContext, false, token)); } } else if (triggerInfo.CompletionTriggerReason == CompletionTriggerReason.CompletionCommand) { int pos = completionContext.TriggerOffset; if (pos <= 0) { return(null); } tracker.UpdateEngine(); return(HandleCodeCompletion(completionContext, true, default(CancellationToken))); } return(null); }
string GetIndentationString(int offset, DocumentLocation loc) { stateTracker.UpdateEngine(Math.Min(data.Length, offset + 1)); DocumentLine line = data.Document.GetLine(loc.Line); if (line == null) { return(""); } // Get context to the end of the line w/o changing the main engine's state var ctx = (CSharpIndentEngine)stateTracker.Engine.Clone(); for (int max = offset; max < line.Offset + line.Length; max++) { ctx.Push(data.Document.GetCharAt(max)); } // int pos = line.Offset; string curIndent = line.GetIndentation(data.Document); int nlwsp = curIndent.Length; // int o = offset > pos + nlwsp ? offset - (pos + nlwsp) : 0; if (!stateTracker.Engine.LineBeganInsideMultiLineComment || (nlwsp < line.LengthIncludingDelimiter && data.Document.GetCharAt(line.Offset + nlwsp) == '*')) { return(ctx.ThisLineIndent); } return(curIndent); }
public override Task<ICompletionDataList> CodeCompletionCommand (CodeCompletionContext completionContext) { int pos = completionContext.TriggerOffset; if (pos <= 0) return null; tracker.UpdateEngine (); return HandleCodeCompletion (completionContext, true, default(CancellationToken)); }
public override ICompletionDataList CodeCompletionCommand(CodeCompletionContext completionContext) { int pos = completionContext.TriggerOffset; if (pos <= 0) { return(null); } int triggerWordLength = 0; tracker.UpdateEngine(); return(HandleCodeCompletion(completionContext, true, ref triggerWordLength)); }
public override ICompletionDataList CodeCompletionCommand(CodeCompletionContext completionContext) { int pos = completionContext.TriggerOffset; string txt = Editor.GetText(pos - 1, pos); int triggerWordLength = 0; if (txt.Length > 0) { tracker.UpdateEngine(); return(HandleCodeCompletion((CodeCompletionContext)completionContext, true, ref triggerWordLength)); } return(null); }
public override void CorrectIndenting(PolicyContainer policyParent, IEnumerable <string> mimeTypeChain, TextEditorData data, int line) { LineSegment lineSegment = data.Document.GetLine(line); if (lineSegment == null) { return; } var policy = policyParent.Get <CSharpFormattingPolicy> (mimeTypeChain); var tracker = new DocumentStateTracker <CSharpIndentEngine> (new CSharpIndentEngine(policy), data); tracker.UpdateEngine(lineSegment.Offset); for (int i = lineSegment.Offset; i < lineSegment.Offset + lineSegment.EditableLength; i++) { tracker.Engine.Push(data.Document.GetCharAt(i)); } string curIndent = lineSegment.GetIndentation(data.Document); int nlwsp = curIndent.Length; if (!tracker.Engine.LineBeganInsideMultiLineComment || (nlwsp < lineSegment.Length && data.Document.GetCharAt(lineSegment.Offset + nlwsp) == '*')) { // Possibly replace the indent string newIndent = tracker.Engine.ThisLineIndent; if (newIndent != curIndent) { data.Replace(lineSegment.Offset, nlwsp, newIndent); } } tracker.Dispose(); }
public override void CorrectIndenting (object textEditorData, int line) { TextEditorData data = (TextEditorData)textEditorData; LineSegment lineSegment = data.Document.GetLine (line); if (lineSegment == null) return; IEnumerable<string> types = MonoDevelop.Ide.DesktopService.GetMimeTypeInheritanceChain (CSharpFormatter.MimeType); var policy = MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<CSharpFormattingPolicy> (types); DocumentStateTracker<CSharpIndentEngine> tracker = new DocumentStateTracker<CSharpIndentEngine> (new CSharpIndentEngine (policy), data); tracker.UpdateEngine (lineSegment.Offset); for (int i = lineSegment.Offset; i < lineSegment.Offset + lineSegment.EditableLength; i++) { tracker.Engine.Push (data.Document.GetCharAt (i)); } string curIndent = lineSegment.GetIndentation (data.Document); int nlwsp = curIndent.Length; if (!tracker.Engine.LineBeganInsideMultiLineComment || (nlwsp < lineSegment.Length && data.Document.GetCharAt (lineSegment.Offset + nlwsp) == '*')) { // Possibly replace the indent string newIndent = tracker.Engine.ThisLineIndent; if (newIndent != curIndent) data.Replace (lineSegment.Offset, nlwsp, newIndent); } tracker.Dispose (); }
DocumentStateTracker<CSharpIndentEngine> CreateTracker (TextEditorData data) { var policy = PolicyService.InvariantPolicies.Get <CSharpFormattingPolicy> ("text/x-csharp"); var textStylePolicy = PolicyService.InvariantPolicies.Get <TextStylePolicy> ("text/x-csharp"); var result = new DocumentStateTracker<CSharpIndentEngine> (new CSharpIndentEngine (policy, textStylePolicy), data); result.UpdateEngine (); return result; }
void HandleTextPaste(int insertionOffset, string text, int insertedChars) { if (!Policy.IndentPastedCodeLines) { return; } using (Editor.OpenUndoGroup()) { var documentLine = Editor.GetLineByOffset(insertionOffset + insertedChars); while (documentLine != null && insertionOffset < documentLine.EndOffset) { stateTracker.UpdateEngine(documentLine.Offset); DoReSmartIndent(documentLine.Offset); documentLine = documentLine.PreviousLine; } } }
DocumentStateTracker <CSharpIndentEngine> CreateTracker(TextEditorData data) { var policy = PolicyService.InvariantPolicies.Get <CSharpFormattingPolicy> ("text/x-csharp"); var textStylePolicy = PolicyService.InvariantPolicies.Get <TextStylePolicy> ("text/x-csharp"); var result = new DocumentStateTracker <CSharpIndentEngine> (new CSharpIndentEngine(policy, textStylePolicy), data); result.UpdateEngine(); return(result); }
void HandleTextPaste(int insertionOffset, string text, int insertedChars) { // // Trim blank spaces on text paste, see: Bug 511 - Trim blank spaces when copy-pasting // if (OnTheFlyFormatting) { // int i = insertionOffset + insertedChars; // bool foundNonWsFollowUp = false; // // var line = Document.Editor.GetLineByOffset (i); // if (line != null) { // for (int j = 0; j < line.Offset + line.Length; j++) { // var ch = Document.Editor.GetCharAt (j); // if (ch != ' ' && ch != '\t') { // foundNonWsFollowUp = true; // break; // } // } // } // // if (!foundNonWsFollowUp) { // while (i > insertionOffset) { // char ch = Document.Editor.GetCharAt (i - 1); // if (ch != ' ' && ch != '\t') // break; // i--; // } // int delta = insertionOffset + insertedChars - i; // if (delta > 0) { // Editor.Caret.Offset -= delta; // Editor.Remove (insertionOffset + insertedChars - delta, delta); // } // } // } var documentLine = Editor.GetLineByOffset(insertionOffset + insertedChars); while (documentLine != null && insertionOffset < documentLine.EndOffset) { stateTracker.UpdateEngine(documentLine.Offset); DoReSmartIndent(documentLine.Offset); documentLine = documentLine.PreviousLine; } }
public void StateShouldBeRazorRootStateAfterCodeBlock () { editor.Text = @"@{ } "; var parser = new XmlParser (new RazorRootState (), false); var tracker = new DocumentStateTracker<XmlParser> (parser, editor); editor.CaretLine = 3; tracker.UpdateEngine (); Assert.IsInstanceOf<RazorRootState> (tracker.Engine.CurrentState); }
public void StateShouldBeRazorRootStateAfterCodeBlock() { editor.Text = @"@{ } "; var parser = new XmlParser(new RazorRootState(), false); var tracker = new DocumentStateTracker <XmlParser> (parser, editor); editor.CaretLine = 3; tracker.UpdateEngine(); Assert.IsInstanceOf <RazorRootState> (tracker.Engine.CurrentState); }
public override void CorrectIndenting(object textEditorData, int line) { TextEditorData data = (TextEditorData)textEditorData; LineSegment lineSegment = data.Document.GetLine(line); if (lineSegment == null) { return; } IEnumerable <string> types = MonoDevelop.Ide.DesktopService.GetMimeTypeInheritanceChain(CSharpFormatter.MimeType); var policy = MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy <CSharpFormattingPolicy> (types); DocumentStateTracker <CSharpIndentEngine> tracker = new DocumentStateTracker <CSharpIndentEngine> (new CSharpIndentEngine(policy), data); tracker.UpdateEngine(lineSegment.Offset); for (int i = lineSegment.Offset; i < lineSegment.Offset + lineSegment.EditableLength; i++) { tracker.Engine.Push(data.Document.GetCharAt(i)); } string curIndent = lineSegment.GetIndentation(data.Document); int nlwsp = curIndent.Length; // int cursor = data.Caret.Offset; // int pos = lineSegment.Offset; // int offset = cursor > pos + nlwsp ? cursor - (pos + nlwsp) : 0; if (!tracker.Engine.LineBeganInsideMultiLineComment || (nlwsp < lineSegment.Length && data.Document.GetCharAt(lineSegment.Offset + nlwsp) == '*')) { // Possibly replace the indent string newIndent = tracker.Engine.ThisLineIndent; // int newIndentLength = newIndent.Length; if (newIndent != curIndent) { data.Replace(lineSegment.Offset, nlwsp, newIndent); } } /* * string endIndent = tracker.Engine.ThisLineIndent; * string indent = endIndent.Length < beginIndent.Length ? endIndent : beginIndent; * if (indent != curIndent) * data.Replace (lineSegment.Offset, curIndent.Length, indent); */ tracker.Dispose(); }
public override bool KeyPress(Gdk.Key key, char keyChar, Gdk.ModifierType modifier) { cursorPositionBeforeKeyPress = textEditorData.Caret.Offset; bool isSomethingSelected = textEditorData.IsSomethingSelected; if (key == Gdk.Key.BackSpace && textEditorData.Caret.Offset == lastInsertedSemicolon) { textEditorData.Document.Undo(); lastInsertedSemicolon = -1; return(false); } lastInsertedSemicolon = -1; if (keyChar == ';' && !(textEditorData.CurrentMode is TextLinkEditMode) && !DoInsertTemplate() && !isSomethingSelected && PropertyService.Get("SmartSemicolonPlacement", false)) { bool retval = base.KeyPress(key, keyChar, modifier); LineSegment curLine = textEditorData.Document.GetLine(textEditorData.Caret.Line); string text = textEditorData.Document.GetTextAt(curLine); if (text.EndsWith(";") || text.Trim().StartsWith("for")) { return(retval); } int guessedOffset = GuessSemicolonInsertionOffset(textEditorData, curLine); if (guessedOffset != textEditorData.Caret.Offset) { textEditorData.Document.EndAtomicUndo(); textEditorData.Document.BeginAtomicUndo(); textEditorData.Remove(textEditorData.Caret.Offset - 1, 1); textEditorData.Caret.Offset = guessedOffset; lastInsertedSemicolon = textEditorData.Caret.Offset + 1; retval = base.KeyPress(key, keyChar, modifier); } return(retval); } if (key == Gdk.Key.Tab && TextEditorProperties.TabIsReindent && !(textEditorData.CurrentMode is TextLinkEditMode) && !DoInsertTemplate() && !isSomethingSelected) { int cursor = textEditorData.Caret.Offset; if (TextEditorProperties.TabIsReindent && stateTracker.Engine.IsInsideVerbatimString) { // insert normal tab inside @" ... " if (textEditorData.IsSomethingSelected) { textEditorData.SelectedText = "\t"; } else { textEditorData.Insert(cursor, "\t"); textEditorData.Caret.Offset++; } textEditorData.Document.CommitLineUpdate(textEditorData.Caret.Line); } else if (TextEditorProperties.TabIsReindent && cursor >= 1) { if (textEditorData.Caret.Column > 1) { int delta = cursor - this.cursorPositionBeforeKeyPress; if (delta < 2 && delta > 0) { textEditorData.Remove(cursor - delta, delta); textEditorData.Caret.Offset = cursor - delta; textEditorData.Document.CommitLineUpdate(textEditorData.Caret.Line); } } stateTracker.UpdateEngine(); DoReSmartIndent(); } return(false); } //do the smart indent if (TextEditorProperties.IndentStyle == IndentStyle.Smart) { //capture some of the current state int oldBufLen = textEditorData.Length; int oldLine = textEditorData.Caret.Line + 1; bool hadSelection = textEditorData.IsSomethingSelected; //pass through to the base class, which actually inserts the character //and calls HandleCodeCompletion etc to handles completion DoPreInsertionSmartIndent(key); bool retval = base.KeyPress(key, keyChar, modifier); //handle inserted characters if (textEditorData.Caret.Offset <= 0 || textEditorData.IsSomethingSelected) { return(retval); } lastCharInserted = TranslateKeyCharForIndenter(key, keyChar, textEditorData.GetCharAt(textEditorData.Caret.Offset - 1)); if (lastCharInserted == '\0') { return(retval); } stateTracker.UpdateEngine(); bool reIndent = false; if (key == Gdk.Key.Return && modifier == Gdk.ModifierType.ControlMask) { FixLineStart(textEditorData.Caret.Line + 1); } else { if (!(oldLine == textEditorData.Caret.Line + 1 && lastCharInserted == '\n') && (oldBufLen != textEditorData.Length || lastCharInserted != '\0')) { DoPostInsertionSmartIndent(lastCharInserted, hadSelection, out reIndent); } } //reindent the line after the insertion, if needed //N.B. if the engine says we need to reindent, make sure that it's because a char was //inserted rather than just updating the stack due to moving around stateTracker.UpdateEngine(); bool automaticReindent = (stateTracker.Engine.NeedsReindent && lastCharInserted != '\0'); if (reIndent || automaticReindent) { DoReSmartIndent(); } if (lastCharInserted == '\n') { RunFormatter(); stateTracker.UpdateEngine(); // DoReSmartIndent (); } stateTracker.UpdateEngine(); lastCharInserted = '\0'; return(retval); } if (TextEditorProperties.IndentStyle == IndentStyle.Auto && TextEditorProperties.TabIsReindent && key == Gdk.Key.Tab) { bool retval = base.KeyPress(key, keyChar, modifier); DoReSmartIndent(); return(retval); } //pass through to the base class, which actually inserts the character //and calls HandleCodeCompletion etc to handles completion return(base.KeyPress(key, keyChar, modifier)); }
string GetIndent(int lineNumber, int column) { stateTracker.UpdateEngine(data.Document.LocationToOffset(lineNumber, column)); return(stateTracker.Engine.NewLineIndent); }
void HandleTextPaste(int insertionOffset, string text, int insertedChars) { if (document.Editor.Options.IndentStyle == IndentStyle.None || document.Editor.Options.IndentStyle == IndentStyle.Auto) { return; } var startLine = Editor.GetLineByOffset(insertionOffset); var endLine = Editor.GetLineByOffset(insertionOffset + insertedChars); using (var undo = Editor.OpenUndoGroup()) { // // Trim blank spaces on text paste, see: Bug 511 - Trim blank spaces when copy-pasting // if (OnTheFlyFormatting) { // int i = insertionOffset + insertedChars; // bool foundNonWsFollowUp = false; // // var line = Document.Editor.GetLineByOffset (i); // if (line != null) { // for (int j = 0; j < line.Offset + line.Length; j++) { // var ch = Document.Editor.GetCharAt (j); // if (ch != ' ' && ch != '\t') { // foundNonWsFollowUp = true; // break; // } // } // } // // if (!foundNonWsFollowUp) { // while (i > insertionOffset) { // char ch = Document.Editor.GetCharAt (i - 1); // if (ch != ' ' && ch != '\t') // break; // i--; // } // int delta = insertionOffset + insertedChars - i; // if (delta > 0) { // Editor.Caret.Offset -= delta; // Editor.Remove (insertionOffset + insertedChars - delta, delta); // } // } // } var curLine = startLine; while (true) { if (curLine == null) { break; } var curLineOffset = curLine.Offset; stateTracker.UpdateEngine(curLineOffset); if (!stateTracker.Engine.IsInsideOrdinaryCommentOrString) { // The Indent engine doesn't really handle pre processor directives very well. if (IsPreprocessorDirective(curLine)) { Editor.Replace(curLineOffset, curLine.Length, stateTracker.Engine.NewLineIndent + Editor.GetTextAt(curLine).TrimStart()); } else { int pos = curLineOffset; string curIndent = curLine.GetIndentation(textEditorData.Document); int nlwsp = curIndent.Length; if (!stateTracker.Engine.LineBeganInsideMultiLineComment || (nlwsp < curLine.LengthIncludingDelimiter && textEditorData.Document.GetCharAt(curLineOffset + nlwsp) == '*')) { // Possibly replace the indent stateTracker.UpdateEngine(curLineOffset + curLine.Length); string newIndent = stateTracker.Engine.ThisLineIndent; if (newIndent != curIndent) { if (CompletionWindowManager.IsVisible) { if (pos < CompletionWindowManager.CodeCompletionContext.TriggerOffset) { CompletionWindowManager.CodeCompletionContext.TriggerOffset -= nlwsp; } } textEditorData.Replace(pos, nlwsp, newIndent); textEditorData.Document.CommitLineUpdate(textEditorData.Caret.Line); } } } } if (curLine == endLine) { break; } curLine = curLine.NextLine; } textEditorData.FixVirtualIndentation(); } }
public override bool KeyPress(Gdk.Key key, char keyChar, Gdk.ModifierType modifier) { bool skipFormatting = StateTracker.Engine.IsInsideOrdinaryCommentOrString || StateTracker.Engine.IsInsidePreprocessorDirective; cursorPositionBeforeKeyPress = textEditorData.Caret.Offset; bool isSomethingSelected = textEditorData.IsSomethingSelected; if (key == Gdk.Key.BackSpace && textEditorData.Caret.Offset == lastInsertedSemicolon) { textEditorData.Document.Undo(); lastInsertedSemicolon = -1; return(false); } lastInsertedSemicolon = -1; if (keyChar == ';' && !(textEditorData.CurrentMode is TextLinkEditMode) && !DoInsertTemplate() && !isSomethingSelected && PropertyService.Get( "SmartSemicolonPlacement", false )) { bool retval = base.KeyPress(key, keyChar, modifier); DocumentLine curLine = textEditorData.Document.GetLine(textEditorData.Caret.Line); string text = textEditorData.Document.GetTextAt(curLine); if (text.EndsWith(";") || text.Trim().StartsWith("for")) { return(retval); } int guessedOffset = GuessSemicolonInsertionOffset(textEditorData, curLine); if (guessedOffset != textEditorData.Caret.Offset) { using (var undo = textEditorData.OpenUndoGroup()) { textEditorData.Remove(textEditorData.Caret.Offset - 1, 1); textEditorData.Caret.Offset = guessedOffset; lastInsertedSemicolon = textEditorData.Caret.Offset + 1; retval = base.KeyPress(key, keyChar, modifier); } } return(retval); } if (key == Gdk.Key.Tab) { stateTracker.UpdateEngine(); if (stateTracker.Engine.IsInsideStringLiteral) { var lexer = new CSharpCompletionEngineBase.MiniLexer(textEditorData.Document.GetTextAt(0, textEditorData.Caret.Offset)); lexer.Parse(); if (lexer.IsInString) { textEditorData.InsertAtCaret("\\t"); return(false); } } } if (key == Gdk.Key.Tab && DefaultSourceEditorOptions.Instance.TabIsReindent && !CompletionWindowManager.IsVisible && !(textEditorData.CurrentMode is TextLinkEditMode) && !DoInsertTemplate() && !isSomethingSelected) { int cursor = textEditorData.Caret.Offset; if (stateTracker.Engine.IsInsideVerbatimString) { // insert normal tab inside @" ... " if (textEditorData.IsSomethingSelected) { textEditorData.SelectedText = "\t"; } else { textEditorData.Insert(cursor, "\t"); textEditorData.Caret.Offset++; } textEditorData.Document.CommitLineUpdate(textEditorData.Caret.Line); } else if (cursor >= 1) { if (textEditorData.Caret.Column > 1) { int delta = cursor - this.cursorPositionBeforeKeyPress; if (delta < 2 && delta > 0) { textEditorData.Remove(cursor - delta, delta); textEditorData.Caret.Offset = cursor - delta; textEditorData.Document.CommitLineUpdate(textEditorData.Caret.Line); } } stateTracker.UpdateEngine(); DoReSmartIndent(); } return(false); } //do the smart indent if (textEditorData.Options.IndentStyle == IndentStyle.Smart || textEditorData.Options.IndentStyle == IndentStyle.Virtual) { bool retval; //capture some of the current state int oldBufLen = textEditorData.Length; int oldLine = textEditorData.Caret.Line + 1; bool hadSelection = textEditorData.IsSomethingSelected; bool reIndent = false; //pass through to the base class, which actually inserts the character //and calls HandleCodeCompletion etc to handles completion using (var undo = textEditorData.OpenUndoGroup()) { DoPreInsertionSmartIndent(key); } retval = base.KeyPress(key, keyChar, modifier); using (var undo = textEditorData.OpenUndoGroup()) { //handle inserted characters if (textEditorData.Caret.Offset <= 0 || textEditorData.IsSomethingSelected) { return(retval); } lastCharInserted = TranslateKeyCharForIndenter(key, keyChar, textEditorData.GetCharAt(textEditorData.Caret.Offset - 1)); if (lastCharInserted == '\0') { return(retval); } stateTracker.UpdateEngine(); if (key == Gdk.Key.Return && modifier == Gdk.ModifierType.ControlMask) { FixLineStart(textEditorData, stateTracker, textEditorData.Caret.Line + 1); } else { if (!(oldLine == textEditorData.Caret.Line + 1 && lastCharInserted == '\n') && (oldBufLen != textEditorData.Length || lastCharInserted != '\0')) { DoPostInsertionSmartIndent(lastCharInserted, hadSelection, out reIndent); } } //reindent the line after the insertion, if needed //N.B. if the engine says we need to reindent, make sure that it's because a char was //inserted rather than just updating the stack due to moving around stateTracker.UpdateEngine(); bool automaticReindent = (stateTracker.Engine.NeedsReindent && lastCharInserted != '\0'); if (reIndent || automaticReindent) { DoReSmartIndent(); } if (!skipFormatting && keyChar == '}') { RunFormatter(new DocumentLocation(textEditorData.Caret.Location.Line, textEditorData.Caret.Location.Column - 1)); } } stateTracker.UpdateEngine(); lastCharInserted = '\0'; return(retval); } if (textEditorData.Options.IndentStyle == IndentStyle.Auto && DefaultSourceEditorOptions.Instance.TabIsReindent && key == Gdk.Key.Tab) { bool retval = base.KeyPress(key, keyChar, modifier); DoReSmartIndent(); return(retval); } //pass through to the base class, which actually inserts the character //and calls HandleCodeCompletion etc to handles completion var result = base.KeyPress(key, keyChar, modifier); if (!skipFormatting && keyChar == '}') { RunFormatter(new DocumentLocation(textEditorData.Caret.Location.Line, textEditorData.Caret.Location.Column - 1)); } return(result); }
void HandleTextPaste(int insertionOffset, string text, int insertedChars) { if (document.Editor.Options.IndentStyle == IndentStyle.None || document.Editor.Options.IndentStyle == IndentStyle.Auto) { return; } // Just correct the start line of the paste operation - the text is already indented. var curLine = Editor.GetLineByOffset(insertionOffset); var curLineOffset = curLine.Offset; stateTracker.UpdateEngine(curLineOffset); if (!stateTracker.Engine.IsInsideOrdinaryCommentOrString) { // The Indent engine doesn't really handle pre processor directives very well. if (IsPreprocessorDirective(curLine)) { Editor.Replace(curLineOffset, curLine.Length, stateTracker.Engine.NewLineIndent + Editor.GetTextAt(curLine).TrimStart()); } else { int pos = curLineOffset; string curIndent = curLine.GetIndentation(textEditorData.Document); int nlwsp = curIndent.Length; if (!stateTracker.Engine.LineBeganInsideMultiLineComment || (nlwsp < curLine.LengthIncludingDelimiter && textEditorData.Document.GetCharAt(curLineOffset + nlwsp) == '*')) { // Possibly replace the indent stateTracker.UpdateEngine(curLineOffset + curLine.Length); string newIndent = stateTracker.Engine.ThisLineIndent; if (newIndent != curIndent) { if (CompletionWindowManager.IsVisible) { if (pos < CompletionWindowManager.CodeCompletionContext.TriggerOffset) { CompletionWindowManager.CodeCompletionContext.TriggerOffset -= nlwsp; } } textEditorData.Replace(pos, nlwsp, newIndent); textEditorData.Document.CommitLineUpdate(textEditorData.Caret.Line); } } } } textEditorData.FixVirtualIndentation(); }
ICompletionDataProvider HandleCodeCompletion( CodeCompletionContext completionContext, bool forced, ref int triggerWordLength) { tracker.UpdateEngine(); //FIXME: lines in completionContext are zero-indexed, but ILocation and buffer are 1-indexed. //This could easily cause bugs. int line = completionContext.TriggerLine + 1, col = completionContext.TriggerLineOffset; ITextBuffer buf = this.Buffer; // completionChar may be a space even if the current char isn't, when ctrl-space is fired t int currentPosition = buf.CursorPosition - 1; char currentChar = buf.GetCharAt(currentPosition); char previousChar = buf.GetCharAt(currentPosition - 1); //decide whether completion will be auto-activated, to avoid unnecessary //parsing, which hurts editor responsiveness if (!forced) { // if (tracker.Engine.CurrentState is S.XmlFreeState && !(currentChar == '<' || currentChar == '>')) { return(null); } if (tracker.Engine.CurrentState is S.XmlNameState && tracker.Engine.CurrentState.Parent is S.XmlAttributeState && previousChar != ' ') { return(null); } if (tracker.Engine.CurrentState is S.XmlAttributeValueState && !(previousChar == '\'' || previousChar == '"' || currentChar == '\'' || currentChar == '"')) { return(null); } } //tag completion if (currentChar == '<') { CodeCompletionDataProvider cp = new CodeCompletionDataProvider(null, GetAmbience()); if (tracker.Engine.CurrentState is S.XmlFreeState) { S.XElement el = tracker.Engine.Nodes.Peek() as S.XElement; AddTagCompletionData(cp, el); } return(cp); } //closing tag completion if (tracker.Engine.CurrentState is S.XmlFreeState && currentPosition - 1 > 0 && currentChar == '>') { //get name of current node in document that's being ended S.XElement el = tracker.Engine.Nodes.Peek() as S.XElement; if (el != null && el.Position.End >= currentPosition && !el.IsClosed && el.IsNamed) { CodeCompletionDataProvider cp = new CodeCompletionDataProvider(null, GetAmbience()); cp.AddCompletionData( new MonoDevelop.XmlEditor.Completion.XmlTagCompletionData( String.Concat("</", el.Name.FullName, ">"), 0, true) ); return(cp); } } //attributes names within tags if (tracker.Engine.CurrentState is S.XmlTagState && forced || (tracker.Engine.CurrentState is S.XmlNameState && tracker.Engine.CurrentState.Parent is S.XmlAttributeState && tracker.Engine.CurrentStateLength == 1) ) { int peekp = (tracker.Engine.CurrentState is S.XmlTagState) ? 0 : 1; S.XElement el = (S.XElement)tracker.Engine.Nodes.Peek(peekp); // HACK S.XElement pel = tracker.Engine.Nodes.Peek(peekp + 1) as S.XElement; if (el.Parent == null && pel != null) { pel.AddChildNode(el); } //attributes if (el != null && el.Name.IsValid && (forced || char.IsWhiteSpace(currentChar) || (char.IsWhiteSpace(previousChar) && char.IsLetter(currentChar)))) { CodeCompletionDataProvider cp = new CodeCompletionDataProvider(null, GetAmbience()); if (!forced) { triggerWordLength = 1; } AddAttributeCompletionData(cp, el); return(cp); } } //attribute values //determine whether to trigger completion within attribute values quotes if ((tracker.Engine.CurrentState is S.XmlDoubleQuotedAttributeValueState || tracker.Engine.CurrentState is S.XmlSingleQuotedAttributeValueState) //trigger on the opening quote && (tracker.Engine.CurrentStateLength == 0 //or trigger on first letter of value, if unforced || (!forced && tracker.Engine.CurrentStateLength == 1)) ) { S.XAttribute att = (S.XAttribute)tracker.Engine.Nodes.Peek(); if (att.IsNamed) { S.XElement el = (S.XElement)tracker.Engine.Nodes.Peek(1); // HACK S.XElement pel = tracker.Engine.Nodes.Peek(2) as S.XElement; if (el.Parent == null && pel != null) { pel.AddChildNode(el); } char next = ' '; if (currentPosition + 1 < buf.Length) { next = buf.GetCharAt(currentPosition + 1); } char compareChar = (tracker.Engine.CurrentStateLength == 0)? currentChar : previousChar; Console.WriteLine("ppa: " + att.Value); if ((compareChar == '"' || compareChar == '\'') && (next == compareChar || char.IsWhiteSpace(next)) ) { //if triggered by first letter of value, grab that letter if (tracker.Engine.CurrentStateLength == 1) { triggerWordLength = 1; } CodeCompletionDataProvider cp = new CodeCompletionDataProvider(null, GetAmbience()); AddAttributeValueCompletionData(cp, el, att); return(cp); } } } return(null); }