Exemplo n.º 1
0
    /// <summary>
    /// Inserts one or more statements at current line. With correct position, indentation, etc.
    /// If editor is null or readonly, prints in output.
    /// Async if called from non-main thread.
    /// </summary>
    /// <param name="s">Text. The function ignores "\r\n" at the end. Does nothing if null.</param>
    /// <param name="separate">Prepend/append empty line to separate from surrounding code if need. If null, does it if <i>s</i> contains '\n'.</param>
    public static void Statements(string s, ICSFlags flags = 0, bool?separate = null)
    {
        if (s == null)
        {
            return;
        }
        bool sep = separate ?? s.Contains('\n');

        if (Environment.CurrentManagedThreadId == 1)
        {
            _Statements(s, flags, sep);
        }
        else
        {
            App.Dispatcher.InvokeAsync(() => _Statements(s, flags, sep));
        }
    }
Exemplo n.º 2
0
    static void _Statements(string s, ICSFlags flags, bool separate)
    {
        if (!App.Hmain.IsVisible)
        {
            App.ShowWindow();
        }
        if (!CodeInfo.GetContextAndDocument(out var k, metaToo: true))
        {
            print.it(s);
            return;
        }
        var root  = k.syntaxRoot;
        var code  = k.code;
        var pos   = k.pos;
        var token = root.FindToken(pos);
        var node  = token.Parent;

        //get the best valid insertion place

        bool havePos = false;
        var  last    = root.AttributeLists.LastOrDefault() as SyntaxNode
                       ?? root.Usings.LastOrDefault() as SyntaxNode
                       ?? root.Externs.LastOrDefault() as SyntaxNode
                       ?? root.GetDirectives(o => o is DefineDirectiveTriviaSyntax).LastOrDefault();

        if (last != null)
        {
            int e1 = last.FullSpan.End;
            if (havePos = pos <= e1)
            {
                pos = e1;
            }
        }

        if (!havePos)
        {
            var members = root.Members;
            if (members.Any())
            {
                var g           = members.LastOrDefault(o => o is GlobalStatementSyntax);
                int posAfterTLS = g?.FullSpan.End ?? members.First().FullSpan.Start;

                bool done1 = false;
                if (node is BlockSyntax)
                {
                    done1 = node.Span.ContainsInside(pos);
                }
                else if (node is MemberDeclarationSyntax)
                {
                    done1 = true;
                    //don't use posAfterTLS if before the first type
                    bool here = node == members.FirstOrDefault(o => o is not GlobalStatementSyntax) && pos <= node.SpanStart;
                    pos = Math.Min(pos, here ? node.SpanStart : posAfterTLS);
                }
                else if (node is CompilationUnitSyntax && g != members[^ 1])                    //after types
                {
                    done1 = true;
                    pos   = Math.Min(pos, posAfterTLS);
                }
                if (!done1)
                {
                    for (; node is not CompilationUnitSyntax; node = node.Parent)
                    {
                        //CiUtil.PrintNode(node);
                        if (node is StatementSyntax)
                        {
                            var pa = node.Parent;
                            if (node is BlockSyntax && pa is not(BlockSyntax or GlobalStatementSyntax))
                            {
                                continue;
                            }
                            var span = node.Span;
                            if (havePos = pos >= span.End && token.IsKind(SyntaxKind.CloseBraceToken))
                            {
                                pos = node.FullSpan.End;
                            }
                            else if (havePos = pos >= span.Start)
                            {
                                pos = span.Start;
                            }
                            break;
                        }
                        if (node is MemberDeclarationSyntax)
                        {
                            pos = posAfterTLS;
                            break;
                        }
                    }
                }

                havePos |= pos == posAfterTLS;
            }
        }

        if (k.meta.end > 0 && pos <= k.meta.end)
        {
            havePos = true;
            pos     = k.meta.end;
            if (code.Eq(pos, "\r\n"))
            {
                pos += 2;
            }
            else if (code.Eq(pos, '\n'))
            {
                pos++;
            }
        }

        if (!havePos)           //if in comments or directive or disabled code, move to the start of trivia or line
        {
            var trivia = root.FindTrivia(pos);
            var tk     = trivia.Kind();
            if (tk is not(SyntaxKind.EndOfLineTrivia or SyntaxKind.None))
            {
                if (tk == SyntaxKind.DisabledTextTrivia)
                {
                    while (pos > 0 && code[pos - 1] != '\n')
                    {
                        pos--;
                    }
                }
                else
                {
                    pos = trivia.FullSpan.Start;
                }
                //rejected: move to the start of entire #if ... block.
                //	Rare, not easy, may be far, and maybe user wants to insert into disabled code.
            }
        }

        //rename symbols in s if need

        try { _RenameNewSymbols(ref s, k.document, node, pos); }
        catch (Exception e1) { Debug_.Print(e1); }

        //indent, newlines

        string breakLine = null;

        for (; pos > 0 && code[pos - 1] != '\n'; pos--)
        {
            if (code[pos - 1] is not(' ' or '\t'))
            {
                breakLine = "\r\n"; break;
            }
        }
        int replTo = pos; while (replTo < code.Length && code[replTo] is ' ' or '\t')
        {
            replTo++;
        }

        var d = k.sci;

        var t2 = root.FindToken(pos); if (t2.SpanStart >= pos)
        {
            t2 = t2.GetPreviousToken();
        }
        bool afterOpenBrace   = t2.IsKind(SyntaxKind.OpenBraceToken);
        bool beforeCloseBrace = replTo < code.Length && code[replTo] == '}';

        int indent = d.zLineIndentationFromPos(true, pos);

        if (afterOpenBrace && breakLine != null && !(t2.Parent is BlockSyntax bs1 && bs1.Parent is GlobalStatementSyntax))
        {
            indent++;
        }