Example #1
1
		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 ();
		}
Example #2
0
        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));
        }
Example #6
0
        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);
        }
Example #7
0
        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();
        }
Example #8
0
		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;
		}
Example #10
0
        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);
        }
Example #12
0
        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();
        }
Example #16
0
        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));
        }
Example #17
0
 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();
            }
        }
Example #19
0
        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);
        }
Example #20
0
        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();
        }
Example #21
0
        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);
        }