Пример #1
0
def list_tests(
        completion_context: ICompletionContext) -> List[ITestInfoTypedDict]:
    from robotframework_ls.impl import ast_utils
    from robotframework_ls.impl import robot_constants

    ast = completion_context.get_ast()
    completion_context.check_cancelled()

    ret: List[ITestInfoTypedDict] = []
    node: NodeInfo
    for node in ast_utils.iter_tests(ast):
        completion_context.check_cancelled()
        try:

            test_case_name_token = node.node.header.get_token(
                robot_constants.TESTCASE_NAME)
            if test_case_name_token is None:
                # Old versions have slashes and not spaces as a separator.
                test_case_name_token = node.node.header.get_token(
                    robot_constants.TESTCASE_NAME.replace(" ", "_"))

            ret.append({
                "uri": completion_context.doc.uri,
                "path": completion_context.doc.path,
                "name": test_case_name_token.value,
            })
        except Exception:
            log.exception("Error listing tests in document.")

    return ret
Пример #2
0
def _collect_libraries_keywords(
    completion_context: ICompletionContext, collector: IKeywordCollector
):
    """
    :param CompletionContext completion_context:
    """
    # Get keywords from libraries
    from robotframework_ls.impl.robot_constants import BUILTIN_LIB
    from robocorp_ls_core.lsp import CompletionItemKind

    libraries = completion_context.get_imported_libraries()

    library_infos = set(
        _LibInfo(
            completion_context.token_value_resolving_variables(library.name),
            library.alias,
            False,
        )
        for library in libraries
    )
    library_infos.add(_LibInfo(BUILTIN_LIB, None, True))
    libspec_manager = completion_context.workspace.libspec_manager

    for library_info in library_infos:
        completion_context.check_cancelled()
        if not completion_context.memo.complete_for_library(library_info.name):
            continue

        library_doc = libspec_manager.get_library_info(
            library_info.name,
            create=True,
            current_doc_uri=completion_context.doc.uri,
            builtin=library_info.builtin,
        )
        if library_doc is not None:
            #: :type keyword: KeywordDoc
            for keyword in library_doc.keywords:
                keyword_name = keyword.name
                if collector.accepts(keyword_name):

                    keyword_args = []
                    if keyword.args:
                        keyword_args = keyword.args

                    collector.on_keyword(
                        _KeywordFoundFromLibrary(
                            library_doc,
                            keyword,
                            keyword_name,
                            keyword_args,
                            completion_context,
                            CompletionItemKind.Method,
                            library_alias=library_info.alias,
                        )
                    )
Пример #3
0
def find_definition(
        completion_context: ICompletionContext) -> Sequence[IDefinition]:
    """
    :note:
        Definitions may be found even if a given source file no longer exists
        at this place (callers are responsible for validating entries).
    """
    from robotframework_ls.impl import ast_utils
    from robotframework_ls.impl.string_matcher import RobotStringMatcher
    from robotframework_ls.impl.variable_completions import collect_variables

    token_info = completion_context.get_current_token()

    if token_info is not None:
        matches = find_keyword_definition(completion_context, token_info)
        if matches is not None:
            return matches

        token = ast_utils.get_library_import_name_token(
            token_info.node, token_info.token)
        if token is not None:
            libspec_manager = completion_context.workspace.libspec_manager
            completion_context.check_cancelled()
            library_doc = libspec_manager.get_library_info(
                token.value,
                create=True,
                current_doc_uri=completion_context.doc.uri,
                arguments=token_info.node.args,
                alias=token_info.node.alias)
            if library_doc is not None:
                definition = _DefinitionFromLibrary(library_doc)
                return [definition]

        token = ast_utils.get_resource_import_name_token(
            token_info.node, token_info.token)
        if token is not None:
            completion_context.check_cancelled()
            resource_import_as_doc = completion_context.get_resource_import_as_doc(
                token_info.node)
            if resource_import_as_doc is not None:
                return [_DefinitionFromResource(resource_import_as_doc)]

    token_info = completion_context.get_current_variable()
    if token_info is not None:

        token = token_info.token
        value = token.value

        collector = _FindDefinitionVariablesCollector(
            completion_context.sel, token, RobotStringMatcher(value))
        collect_variables(completion_context, collector)
        return collector.matches

    return []
Пример #4
0
def _collect_following_imports(completion_context: ICompletionContext,
                               collector):
    completion_context.check_cancelled()
    if completion_context.memo.follow_import(completion_context.doc.uri):
        # i.e.: prevent collecting keywords for the same doc more than once.

        _collect_current_doc_keywords(completion_context, collector)

        _collect_resource_imports_keywords(completion_context, collector)

        _collect_libraries_keywords(completion_context, collector)
Пример #5
0
def _collect_following_imports(completion_context: ICompletionContext,
                               collector: _Collector):
    completion_context.check_cancelled()
    if completion_context.memo.follow_import_variables(
            completion_context.doc.uri):
        # i.e.: prevent collecting variables for the same doc more than once.

        _collect_current_doc_variables(completion_context, collector)

        _collect_resource_imports_variables(completion_context, collector)

        _collect_variable_imports_variables(completion_context, collector)
Пример #6
0
def collect_analysis_errors(completion_context: ICompletionContext):
    errors = []
    collector = _KeywordsCollector()
    collect_keywords(completion_context, collector)

    ast = completion_context.get_ast()
    for keyword_usage_info in ast_utils.iter_keyword_usage_tokens(ast):
        completion_context.check_cancelled()
        normalized_name = normalize_robot_name(keyword_usage_info.name)
        if not collector.contains_keyword(normalized_name):

            # There's not a direct match, but the library name may be builtin
            # into the keyword name, so, check if we have a match that way.

            node = keyword_usage_info.node
            error = create_error_from_node(
                node,
                "Undefined keyword: %s." % (keyword_usage_info.name, ),
                tokens=[keyword_usage_info.token],
            )

            errors.append(error)
        else:
            multi = collector.check_multiple_keyword_definitions(
                normalized_name)
            if multi is not None:

                node = keyword_usage_info.node
                error = create_error_from_node(
                    node,
                    "Multiple keywords with name '%s' found. Give the full name of the keyword you want to use:\n%s"
                    % (keyword_usage_info.name, "\n".join([
                        f"    {m.library_alias}.{m.keyword_name}"
                        for m in multi
                    ])),
                    tokens=[keyword_usage_info.token],
                )
                errors.append(error)

        if len(errors) >= MAX_ERRORS:
            # i.e.: Collect at most 100 errors
            break

    errors.extend(CodeAnalysisVisitor.find_from(completion_context))

    return errors
Пример #7
0
def code_lens_scratchpad(
        completion_context: ICompletionContext) -> List[CodeLensTypedDict]:
    from robot.api import Token  # noqa
    from robotframework_ls import import_rf_interactive

    import_rf_interactive()

    ast = completion_context.get_ast()
    completion_context.check_cancelled()

    ret: List[CodeLensTypedDict] = []

    for name_token, header, node in _iter_scratchpad_items(ast):
        completion_context.check_cancelled()
        ret.append(
            _create_scratchpad_code_lens(completion_context, name_token,
                                         header, node))

    return ret
def _collect_completions_from_ast(
    ast, completion_context: ICompletionContext, collector
):
    completion_context.check_cancelled()
    from robotframework_ls.impl import ast_utils
    from robot.api import Token

    ast = completion_context.get_ast()
    for variable_node_info in ast_utils.iter_variables(ast):
        variable_node = variable_node_info.node
        token = variable_node.get_token(Token.VARIABLE)
        if token is None:
            continue
        name = token.value
        if name.endswith("="):
            name = name[:-1].rstrip()

        if collector.accepts(name):
            variable_found = _VariableFoundFromToken(
                completion_context, token, variable_node.value, variable_name=name
            )
            collector.on_variable(variable_found)
Пример #9
0
def _collect_completions_from_ast(ast, completion_context: ICompletionContext,
                                  collector):
    from robotframework_ls.impl import ast_utils
    from robocorp_ls_core.lsp import CompletionItemKind

    for keyword in ast_utils.iter_keywords(ast):
        completion_context.check_cancelled()
        keyword_name = keyword.node.name
        if collector.accepts(keyword_name):
            keyword_args = []
            for arg in ast_utils.iter_keyword_arguments_as_str(keyword.node):
                keyword_args.append(KeywordArg(arg))

            collector.on_keyword(
                _KeywordFoundFromAst(
                    ast,
                    keyword.node,
                    keyword_name,
                    keyword_args,
                    completion_context,
                    CompletionItemKind.Function,
                ))
Пример #10
0
def folding_range(
    completion_context: ICompletionContext
) -> List[FoldingRangeTypedDict]:
    from robotframework_ls.impl import ast_utils
    from robotframework_ls.impl.protocols import NodeInfo

    ast = completion_context.get_ast()
    completion_context.check_cancelled()

    ret: List[FoldingRangeTypedDict] = []
    node: NodeInfo
    for node in ast_utils.iter_all_nodes(ast):
        completion_context.check_cancelled()
        try:
            start_line = node.node.lineno - 1
            end_line = node.node.end_lineno - 1
            if end_line > start_line:
                ret.append({"startLine": start_line, "endLine": end_line})
        except Exception:
            log.exception("Error computing range")

    return ret
Пример #11
0
def _collect_completions_from_ast(ast, completion_context: ICompletionContext,
                                  collector):
    completion_context.check_cancelled()
    from robot.api import Token

    for variable_node_info in completion_context.get_all_variables():
        variable_node = variable_node_info.node
        token = variable_node.get_token(Token.VARIABLE)
        if token is None:
            continue
        name = token.value
        if not name:
            continue
        name = name.strip()
        if not name:
            continue
        if name.endswith("="):
            name = name[:-1].rstrip()

        if name.startswith(("&", "@")):
            # Allow referencing dict(&)/list(@) variables as regular ($) variables
            dict_or_list_var = "$" + name[1:]
            if collector.accepts(dict_or_list_var):
                variable_found = _VariableFoundFromToken(
                    completion_context,
                    token,
                    variable_node.value,
                    variable_name=dict_or_list_var,
                )
                collector.on_variable(variable_found)
        if collector.accepts(name):
            variable_found = _VariableFoundFromToken(completion_context,
                                                     token,
                                                     variable_node.value,
                                                     variable_name=name)
            collector.on_variable(variable_found)
Пример #12
0
def code_lens_runs(
        completion_context: ICompletionContext) -> List[CodeLensTypedDict]:
    from robot.api import Token  # noqa
    from robotframework_ls.impl.ast_utils import create_range_from_token

    ast = completion_context.get_ast()
    completion_context.check_cancelled()

    ret: List[CodeLensTypedDict] = []

    start: PositionTypedDict = {"line": 0, "character": 0}
    end: PositionTypedDict = {"line": 0, "character": 0}
    code_lens_range: RangeTypedDict = {"start": start, "end": end}

    sections = ast.sections

    test_case_sections = [
        x for x in sections if x.__class__.__name__ == "TestCaseSection"
    ]

    if len(test_case_sections) > 0:
        # Run Test command
        command: CommandTypedDict = {
            "title":
            "Run Suite",
            "command":
            "robot.runTest",
            "arguments": [{
                "uri": completion_context.doc.uri,
                "path": completion_context.doc.path,
                "name": "*",
            }],
        }

        ret.append({"range": code_lens_range, "command": command})

        # Debug Test command
        command = {
            "title":
            "Debug Suite",
            "command":
            "robot.debugTest",
            "arguments": [{
                "uri": completion_context.doc.uri,
                "path": completion_context.doc.path,
                "name": "*",
            }],
        }

        ret.append({"range": code_lens_range, "command": command})

    for test_case in test_case_sections:
        try:
            for test_node in test_case.body:
                test_case_name_token = test_node.header.get_token(
                    Token.TESTCASE_NAME)
                completion_context.check_cancelled()

                code_lens_range = create_range_from_token(test_case_name_token)

                # Run Test command
                command = {
                    "title":
                    "Run",
                    "command":
                    "robot.runTest",
                    "arguments": [{
                        "uri": completion_context.doc.uri,
                        "path": completion_context.doc.path,
                        "name": test_case_name_token.value,
                    }],
                }

                code_lens_dct: CodeLensTypedDict = {
                    "range": code_lens_range,
                    "command": command,
                }
                ret.append(code_lens_dct)

                # Debug Test command
                command = {
                    "title":
                    "Debug",
                    "command":
                    "robot.debugTest",
                    "arguments": [{
                        "uri": completion_context.doc.uri,
                        "path": completion_context.doc.path,
                        "name": test_node.name,
                    }],
                }

                code_lens_dct = {"range": code_lens_range, "command": command}
                ret.append(code_lens_dct)
        except Exception:
            log.exception("Error computing code lens")

    return ret