Exemplo n.º 1
0
        /// <summary>
        /// Parse text to determine if string being typed at caretPos is in
        /// the context of a comment or string or character
        /// </summary>
        /// <param name="text"> input block of code </param>
        /// <param name="caretPos"> caret position in text at which to determine context </param>
        /// <returns> True if any of above context is true </returns>
        public static bool IsInsideCommentOrString(string text, int caretPos)
        {
            var lexer = new CodeCompletionParser(text);

            lexer.ParseContext(caretPos);
            return
                (lexer.isInSingleComment ||
                 lexer.isInString ||
                 lexer.isInChar ||
                 lexer.isInMultiLineComment);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Given the code that's currently being typed in a CBN,
        /// this function extracts the expression that needs to be code-completed
        /// e.g. given "abc.X[{xyz.b.foo((abc" it returns "abc"
        /// which is the "thing" that needs to be queried for completions
        /// </summary>
        /// <param name="code"></param>
        public static string GetStringToComplete(string code)
        {
            var codeParser = new CodeCompletionParser(code);

            // TODO: Discard complete code statements terminated by ';'
            // and extract only the current line being typed
            for (int i = 0; i < code.Length; ++i)
            {
                codeParser.ParseStringToComplete(code[i]);
            }
            return(codeParser.strPrefix);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Given a block of code that's currently being typed
        /// this returns the method name and the type name on which it is invoked
        /// e.g. "Point.ByCoordinates" returns 'ByCoordinates' as the functionName and 'Point' as functionPrefix
        /// "abc.X[{xyz.b.foo" returns 'foo' as the functionName and 'xyz.b' as the "functionPrefix" on which it is invoked
        /// </summary>
        /// <param name="code"> input code block </param>
        /// <param name="functionName"> output function name </param>
        /// <param name="functionPrefix"> output type or variable on which fn is invoked </param>
        public static void GetFunctionToComplete(string code, out string functionName, out string functionPrefix)
        {
            var codeParser = new CodeCompletionParser(code);

            // TODO: Discard complete code statements terminated by ';'
            // and extract only the current line being typed
            for (int i = 0; i < code.Length; ++i)
            {
                codeParser.ParseStringToComplete(code[i]);
            }
            functionName   = codeParser.functionName;
            functionPrefix = codeParser.functionPrefix;
        }
Exemplo n.º 4
0
        /// <summary>
        /// Call this method to format user codes in the following ways:
        ///
        /// 1. Leading and trailing whitespaces are removed from the original
        ///    string. Characters that qualify as "whitespaces" are: '\n', '\t'
        ///    and ' '.
        ///
        /// 2. Multiple statements on a single line will be broken down further
        ///    into multiple statements. For example, "a = 1; b = 2;" will be
        ///    broken down into two lines: "a = 1;\nb = 2;" (line break denoted
        ///    by the new \n character).
        ///
        /// 3. Leading whitespaces will be removed ony for the first line. This
        ///    is to preserve the indentation for lines other than the first.
        ///
        /// 4. If the resulting codes do not end with a closing curly bracket '}',
        ///    then a semi-colon is appended to the code. This ensures codes like
        ///    "a" will result in codes becoming "a;"
        ///
        /// </summary>
        /// <param name="inputCode">Original code content as typed in by the user.
        /// </param>
        /// <returns>Returns the formatted code with the above process.</returns>
        ///
        public static string FormatUserText(string inputCode)
        {
            if (inputCode == null)
            {
                return(string.Empty);
            }

            // Trailing and preceeding whitespaces removal.
            var charsToTrim = new char[] { '\n', '\t', ' ' };

            inputCode = NormalizeLineBreaks(inputCode);
            inputCode = inputCode.Trim(charsToTrim);

            List <string> statements  = new List <string>();
            var           splitOption = StringSplitOptions.RemoveEmptyEntries;

            // Break the input string into lines based on the \n characters that
            // are already in the string. Note that after breaking the string,
            // each line can still contain multiple statements (e.g. "a = 1; b;"
            // that does not contain a \n between the two statements).
            //
            var lines = inputCode.Split('\n');

            foreach (var line in lines)
            {
                if (line.IndexOf(';') == -1)
                {
                    // The line does not have any semi-colon originally. We know
                    // this is a line by itself, but may or may not represent a
                    // statement. But since this line (potentially an empty one)
                    // exists in the original user string, it needs to go into
                    // the resulting statement list.
                    //
                    var trimmed = line.TrimEnd(charsToTrim);
                    statements.Add(trimmed + "\n");
                }
                else
                {
                    // This line potentially contains more than one statements
                    // (e.g. "a = 1; b = 2;"), or it might even be a single
                    // statement (e.g. "a = 1;  " with trailing spaces). After
                    // breaking each line up into statements, it is important
                    // that only non-empty lines go into the resulting statement
                    // list, and not the empty ones (for the case of "a = 1; ").
                    //
                    var parts = line.Split(new char[] { ';' }, splitOption);
                    foreach (var part in parts)
                    {
                        var trimmed = part.TrimEnd(charsToTrim);
                        if (!string.IsNullOrEmpty(trimmed))
                        {
                            statements.Add(trimmed + ";\n");
                        }
                    }
                }
            }

            // Now join all the statements together into one single code, and
            // remove the final trailing white spaces (including the last \n).
            inputCode = statements.Aggregate("", (curr, stmt) => curr + stmt);
            inputCode = inputCode.TrimEnd(charsToTrim);

            // If after all the processing we do not end up with an empty code,
            // then we may need a semi-colon at the end. This is provided if the
            // code does not end with a comment or string (in which case a
            // trailing semi-colon is not required).
            //
            if (!string.IsNullOrEmpty(inputCode) &&
                !CodeCompletionParser.IsInsideCommentOrString(inputCode, inputCode.Length))
            {
                if (inputCode.EndsWith(";") == false)
                {
                    inputCode = inputCode + ";";
                }
            }

            return(inputCode);
        }