Example #1
0
        /// <summary>
        /// Reparses the code of the current scope and returns the object (either IExpression or ITypeDeclaration derivative)
        /// that is beneath the caret location.
        ///
        /// Used for code completion/symbol resolution.
        /// Mind the extra options that might be passed via the Options parameter.
        /// </summary>
        /// <param name="ctxt">Can be null</param>
        public static ISyntaxRegion GetScopedCodeObject(IEditorData editor,
                                                        ResolverContextStack ctxt = null,
                                                        AstReparseOptions Options = 0)
        {
            if (ctxt == null)
            {
                ctxt = ResolverContextStack.Create(editor);
            }

            var code = editor.ModuleCode;

            int  start         = 0;
            var  startLocation = CodeLocation.Empty;
            bool IsExpression  = false;

            if (ctxt.CurrentContext.ScopedStatement is IExpressionContainingStatement)
            {
                var         exprs      = ((IExpressionContainingStatement)ctxt.CurrentContext.ScopedStatement).SubExpressions;
                IExpression targetExpr = null;

                if (exprs != null)
                {
                    foreach (var ex in exprs)
                    {
                        if ((targetExpr = ExpressionHelper.SearchExpressionDeeply(ex, editor.CaretLocation, true))
                            != ex)
                        {
                            break;
                        }
                    }
                }

                if (targetExpr != null && editor.CaretLocation >= targetExpr.Location && editor.CaretLocation <= targetExpr.EndLocation)
                {
                    startLocation = targetExpr.Location;
                    start         = DocumentHelper.LocationToOffset(editor.ModuleCode, startLocation);
                    IsExpression  = true;
                }
            }

            if (!IsExpression)
            {
                // First check if caret is inside a comment/string etc.
                int lastStart    = -1;
                int lastEnd      = -1;
                var caretContext = CaretContextAnalyzer.GetTokenContext(code, editor.CaretOffset, out lastStart, out lastEnd);

                // Return if comment etc. found
                if (caretContext != TokenContext.None)
                {
                    return(null);
                }

                start = CaretContextAnalyzer.SearchExpressionStart(code, editor.CaretOffset - 1,
                                                                   (lastEnd > 0 && lastEnd < editor.CaretOffset) ? lastEnd : 0);
                startLocation = DocumentHelper.OffsetToLocation(editor.ModuleCode, start);
            }

            if (start < 0 || editor.CaretOffset <= start)
            {
                return(null);
            }

            var expressionCode = code.Substring(start, Options.HasFlag(AstReparseOptions.AlsoParseBeyondCaret) ? code.Length - start : editor.CaretOffset - start);

            var parser = DParser.Create(new StringReader(expressionCode));

            parser.Lexer.SetInitialLocation(startLocation);
            parser.Step();

            if (!IsExpression && Options.HasFlag(AstReparseOptions.OnlyAssumeIdentifierList) && parser.Lexer.LookAhead.Kind == DTokens.Identifier)
            {
                return(parser.IdentifierList());
            }
            else if (IsExpression || parser.IsAssignExpression())
            {
                if (Options.HasFlag(AstReparseOptions.ReturnRawParsedExpression))
                {
                    return(parser.AssignExpression());
                }
                else
                {
                    return(ExpressionHelper.SearchExpressionDeeply(parser.AssignExpression(), editor.CaretLocation, Options.HasFlag(AstReparseOptions.WatchForParamExpressions)));
                }
            }
            else
            {
                return(parser.Type());
            }
        }
Example #2
0
        public override bool KeyPress(Gdk.Key key, char keyChar, Gdk.ModifierType modifier)
        {
            bool skipFormatting = StateTracker.Engine.IsInsideCommentOrString ||
                                  StateTracker.Engine.IsInsidePreprocessorDirective;

            cursorPositionBeforeKeyPress = textEditorData.Caret.Offset;

            if (keyChar == ';' && !(textEditorData.CurrentMode is TextLinkEditMode))
            {
                DoInsertTemplate();
            }

            if (key == Gdk.Key.Tab)
            {
                stateTracker.UpdateEngine();
                if (stateTracker.Engine.IsInsideStringLiteral && !textEditorData.IsSomethingSelected)
                {
                    var tokenCtxt = CaretContextAnalyzer.GetTokenContext(textEditorData.Document.Text, textEditorData.Caret.Offset);
                    if (tokenCtxt == TokenContext.String || tokenCtxt == TokenContext.VerbatimString)
                    {
                        textEditorData.InsertAtCaret("\\t");
                        return(false);
                    }
                }
            }


            if (key == Gdk.Key.Tab && DefaultSourceEditorOptions.Instance.TabIsReindent && !CompletionWindowManager.IsVisible && !(textEditorData.CurrentMode is TextLinkEditMode) && !DoInsertTemplate() && !textEditorData.IsSomethingSelected)
            {
                int cursor = textEditorData.Caret.Offset;
                if (stateTracker.Engine.IsInsideVerbatimString && cursor > 0 && cursor < textEditorData.Document.TextLength && textEditorData.GetCharAt(cursor - 1) == '"')
                {
                    stateTracker.UpdateEngine(cursor + 1);
                }

                if (stateTracker.Engine.IsInsideVerbatimString)
                {
                    // insert normal tab inside r" ... "
                    if (textEditorData.IsSomethingSelected)
                    {
                        textEditorData.SelectedText = "\t";
                    }
                    else
                    {
                        textEditorData.Insert(cursor, "\t");
                    }
                    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);
                }

                bool automaticReindent;
                using (var undo = textEditorData.OpenUndoGroup()) {
                    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();

                    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();
                    automaticReindent = (stateTracker.Engine.NeedsReindent && lastCharInserted != '\0');
                    if (key == Gdk.Key.Return && (reIndent || automaticReindent))
                    {
                        DoReSmartIndent();
                    }
                }

                if (key != Gdk.Key.Return && (reIndent || automaticReindent))
                {
                    using (var undo = textEditorData.OpenUndoGroup()) {
                        DoReSmartIndent();
                    }
                }

                if (!skipFormatting && keyChar == '}')
                {
                    using (var undo = textEditorData.OpenUndoGroup()) {
                        RunFormatter(new DocumentLocation(textEditorData.Caret.Location.Line, textEditorData.Caret.Location.Column));
                    }
                }

                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));
            }
            return(result);
        }
Example #3
0
        /// <summary>
        /// Reparses the code of the current scope and returns the object (either IExpression or ITypeDeclaration derivative)
        /// that is beneath the caret location.
        ///
        /// Used for code completion/symbol resolution.
        /// Mind the extra options that might be passed via the Options parameter.
        /// </summary>
        /// <param name="ctxt">Can be null</param>
        public static ISyntaxRegion GetScopedCodeObject(IEditorData editor,
                                                        AstReparseOptions Options = AstReparseOptions.AlsoParseBeyondCaret,
                                                        ResolutionContext ctxt    = null)
        {
            if (ctxt == null)
            {
                ctxt = ResolutionContext.Create(editor);
            }

            var code = editor.ModuleCode;

            int  start         = 0;
            var  startLocation = CodeLocation.Empty;
            bool IsExpression  = false;

            if (ctxt.CurrentContext.ScopedStatement is IExpressionContainingStatement)
            {
                var         exprs      = ((IExpressionContainingStatement)ctxt.CurrentContext.ScopedStatement).SubExpressions;
                IExpression targetExpr = null;

                if (exprs != null)
                {
                    foreach (var ex in exprs)
                    {
                        if ((targetExpr = ExpressionHelper.SearchExpressionDeeply(ex, editor.CaretLocation))
                            != ex)
                        {
                            break;
                        }
                    }
                }

                if (targetExpr != null && editor.CaretLocation >= targetExpr.Location && editor.CaretLocation <= targetExpr.EndLocation)
                {
                    startLocation = targetExpr.Location;
                    start         = DocumentHelper.GetOffsetByRelativeLocation(editor.ModuleCode, editor.CaretLocation, editor.CaretOffset, startLocation);
                    IsExpression  = true;
                }
            }

            if (!IsExpression)
            {
                // First check if caret is inside a comment/string etc.
                int lastStart = 0;
                int lastEnd   = 0;
                if ((Options & AstReparseOptions.DontCheckForCommentsOrStringSurrounding) == 0)
                {
                    var caretContext = CaretContextAnalyzer.GetTokenContext(code, editor.CaretOffset, out lastStart, out lastEnd);

                    // Return if comment etc. found
                    if (caretContext != TokenContext.None)
                    {
                        return(null);
                    }
                }

                // Could be somewhere in an ITypeDeclaration..

                if (editor.CaretOffset < 0 || editor.CaretOffset >= code.Length)
                {
                    return(null);
                }

                if (Lexer.IsIdentifierPart(code[editor.CaretOffset]))
                {
                    start = editor.CaretOffset;
                }
                else if (editor.CaretOffset > 0 && Lexer.IsIdentifierPart(code[editor.CaretOffset - 1]))
                {
                    start = editor.CaretOffset - 1;
                }


                start = CaretContextAnalyzer.SearchExpressionStart(code, start,
                                                                   (lastEnd > 0 && lastEnd < editor.CaretOffset) ? lastEnd : 0);
                startLocation = DocumentHelper.OffsetToLocation(editor.ModuleCode, start);
            }

            if (start < 0 || editor.CaretOffset < start)
            {
                return(null);
            }

            var sv     = new StringView(code, start, Options.HasFlag(AstReparseOptions.AlsoParseBeyondCaret) ? code.Length - start : editor.CaretOffset - start);
            var parser = DParser.Create(sv);

            parser.Lexer.SetInitialLocation(startLocation);
            parser.Step();

            ITypeDeclaration td;

            if (!IsExpression && Options.HasFlag(AstReparseOptions.OnlyAssumeIdentifierList) && parser.Lexer.LookAhead.Kind == DTokens.Identifier)
            {
                td = parser.IdentifierList();
            }
            else if (IsExpression || parser.IsAssignExpression())
            {
                if (Options.HasFlag(AstReparseOptions.ReturnRawParsedExpression))
                {
                    return(parser.AssignExpression());
                }
                else
                {
                    return(ExpressionHelper.SearchExpressionDeeply(parser.AssignExpression(), editor.CaretLocation));
                }
            }
            else
            {
                td = parser.Type();
            }

            if (Options.HasFlag(AstReparseOptions.ReturnRawParsedExpression))
            {
                return(td);
            }

            while (td != null && td.InnerDeclaration != null && editor.CaretLocation <= td.InnerDeclaration.EndLocation)
            {
                td = td.InnerDeclaration;
            }

            return(td);
        }
Example #4
0
        public override bool KeyPress(Key key, char keyChar, ModifierType modifier)
        {
            var ed = Document.Editor;

            var dPolicy = Document.HasProject ? Document.Project.Policies.Get <DFormattingPolicy> ("text/x-d") :
                          PolicyService.GetDefaultPolicy <DFormattingPolicy> ("text/x-d");

            if (key == Key.Return)
            {
                ed.DeleteSelectedText(true);

                int lastBegin;
                int lastEnd;
                var caretCtxt = CaretContextAnalyzer.GetTokenContext(ed.Text, ed.Caret.Offset, out lastBegin, out lastEnd);

                if (lastBegin >= 0 &&
                    (caretCtxt == TokenContext.BlockComment ||
                     caretCtxt == TokenContext.NestedComment))
                {
                    var charsToInsert = " " +
                                        (caretCtxt == TokenContext.BlockComment ?
                                         '*' :
                                         '+') + " ";

                    var commentBeginIndent = ed.GetLineIndent(ed.GetLineByOffset(lastBegin));

                    ed.InsertAtCaret(
                        Document.Editor.EolMarker +
                        commentBeginIndent +
                        (dPolicy.InsertStarAtCommentNewLine ? charsToInsert : ""));
                    return(false);
                }
            }

            if (Document.Editor.Options.IndentStyle == IndentStyle.Smart || Document.Editor.Options.IndentStyle == IndentStyle.Virtual)
            {
                int newIndentation = 0;

                if (key == Key.Return)
                {
                    ed.InsertAtCaret(Document.Editor.EolMarker);

                    var tr = ed.Document.CreateReader();
                    var cb = DCodeFormatter.NativeFormatterInstance.CalculateIndentation(tr, ed.Caret.Line);
                    tr.Close();

                    newIndentation = cb == null ? 0 : cb.GetLineIndentation(ed.Caret.Line);

                    ed.InsertAtCaret(CalculateIndentationString(newIndentation));

                    return(false);
                }

                else if (keyChar == '{' || keyChar == '}' || keyChar == ':')
                {
                    ed.DeleteSelectedText(true);

                    ed.InsertAtCaret(keyChar.ToString());

                    // Ensure that we aren't in a non-code area right now - automatically trying to format comments is awful
                    int lastBegin;
                    int lastEnd;
                    var caretCtxt = CaretContextAnalyzer.GetTokenContext(ed.Text, ed.Caret.Offset, out lastBegin, out lastEnd);

                    if (lastBegin >= 0 && caretCtxt != TokenContext.None)
                    {
                        return(false);
                    }

                    var origInd             = ed.GetLineIndent(ed.Caret.Line);
                    int originalIndentation = origInd.Length;

                    var tr = ed.Document.CreateReader();
                    var cb = DCodeFormatter.NativeFormatterInstance.CalculateIndentation(tr, ed.Caret.Line);
                    tr.Close();

                    newIndentation = cb == null ? 0 : cb.GetLineIndentation(ed.Caret.Line);
                    var newInd = CalculateIndentationString(newIndentation);

                    if (origInd != newInd)
                    {
                        ed.Replace(
                            Document.Editor.GetLine(ed.Caret.Line).Offset,
                            originalIndentation,
                            newInd);
                    }

                    return(false);
                }
            }

            return(base.KeyPress(key, keyChar, modifier));
        }