Exemplo n.º 1
0
    def __init__(
            self,
            root_uri: str,
            workspace_folders: Optional[List[IWorkspaceFolder]] = None,
            track_file_extensions=(".robot", ".resource"),
    ) -> None:
        from robocorp_ls_core.lsp import WorkspaceFolder

        self._main_thread = threading.current_thread()

        self._root_uri = root_uri
        self._root_uri_scheme = uri_scheme(self._root_uri)
        self._root_path = to_fs_path(self._root_uri)
        self._folders: Dict[str, _WorkspaceFolderWithVirtualFS] = {}
        self._track_file_extensions = track_file_extensions

        # Contains the docs with files considered open.
        self._docs: Dict[str, IDocument] = {}

        # Contains the docs pointing to the filesystem.
        self._filesystem_docs: Dict[str, IDocument] = {}

        if workspace_folders is not None:
            for folder in workspace_folders:
                self.add_folder(folder)

        if root_uri and root_uri not in self._folders:
            as_fs_path = uris.to_fs_path(root_uri)
            name = os.path.basename(as_fs_path)
            self.add_folder(WorkspaceFolder(root_uri, name))
Exemplo n.º 2
0
    def _do_create_libspec_on_get(self, libname, current_doc_uri, arguments,
                                  alias):
        from robocorp_ls_core import uris

        additional_path = None
        abspath = None
        cwd = None
        if current_doc_uri is not None:
            cwd = os.path.dirname(uris.to_fs_path(current_doc_uri))
            if not cwd or not os.path.isdir(cwd):
                cwd = None

        if os.path.isabs(libname):
            abspath = libname

        elif current_doc_uri is not None:
            # relative path: let's make it absolute
            fs_path = os.path.dirname(uris.to_fs_path(current_doc_uri))
            abspath = os.path.abspath(os.path.join(fs_path, libname))

        if abspath:
            additional_path = os.path.dirname(abspath)
            libname = os.path.basename(libname)
            if libname.lower().endswith((".py", ".class", ".java")):
                libname = os.path.splitext(libname)[0]

        if self._create_libspec(libname,
                                additional_path=additional_path,
                                cwd=cwd,
                                arguments=arguments,
                                alias=alias,
                                current_doc_uri=current_doc_uri):
            self.synchronize_internal_libspec_folders()
            return True
        return False
    def get_library_target_filename(
            self,
            libname: str,
            current_doc_uri: Optional[str] = None) -> Optional[str]:
        from robocorp_ls_core import uris

        target_file: Optional[str] = None
        libname_lower = libname.lower()

        if os.path.isabs(libname):
            target_file = libname
        else:
            # Check if it maps to a file in the filesystem
            if current_doc_uri is not None:
                cwd = os.path.dirname(uris.to_fs_path(current_doc_uri))
                if cwd and os.path.isdir(cwd):
                    f = os.path.join(cwd, libname)
                    if os.path.exists(f):
                        target_file = f

                    elif not libname_lower.endswith(".py"):
                        f += ".py"
                        if os.path.exists(f):
                            target_file = f
        return target_file
Exemplo n.º 4
0
    def __init__(
        self,
        verbose: int = 0,
        base_log_file: str = "",
        on_interpreter_message=None,
        uri: str = "",
    ):
        from robotframework_interactive.server.rf_interpreter_ls_config import (
            RfInterpreterRobotConfig,
        )
        from robocorp_ls_core import uris

        assert uri
        self._uri = uri
        self._filename = uris.to_fs_path(uri)
        self._lock_api_client = threading.RLock()
        self._server_process = None
        self._log_extension = ".rf_interpreter"
        self._disposed = False
        # The config allows clients to set the python executable/env.
        self._config: IConfig = RfInterpreterRobotConfig()

        self._verbose = verbose
        self._base_log_file = base_log_file
        self._on_interpreter_message = on_interpreter_message
    def m_text_document__hover(self, **kwargs):
        """
        When hovering over a png in base64 surrounded by double-quotes... something as:
        "iVBORw0KGgo...rest of png in base 64 contents..."

        i.e.: Provide the contents in markdown format to show the actual image from the
        locators.json.
        """
        from robocorp_ls_core import uris
        from robocorp_ls_core.protocols import IDocument
        from robocorp_ls_core.protocols import IDocumentSelection
        from robocorp_ls_core.lsp import Range
        from robocorp_ls_core.lsp import MarkupKind
        from robocorp_ls_core.lsp import MarkupContent

        doc_uri = kwargs["textDocument"]["uri"]
        # Note: 0-based
        line: int = kwargs["position"]["line"]
        col: int = kwargs["position"]["character"]
        if not uris.to_fs_path(doc_uri).endswith("locators.json"):
            return None
        document: IDocument = self._workspace.get_document(
            doc_uri, accept_from_file=True)
        sel: IDocumentSelection = document.selection(line, col)
        current_line: str = sel.current_line
        i: int = current_line.find(
            '"iVBORw0KGgo'
        )  # I.e.: pngs in base64 always start with this prefix.
        if i >= 0:
            current_line = current_line[i + 1:]
            i = current_line.find('"')
            if i >= 0:
                current_line = current_line[0:i]
                image_path = f"data:image/png;base64,{current_line}"
                s = f"![Screenshot]({image_path})"
                return {
                    "contents": MarkupContent(MarkupKind.Markdown,
                                              s).to_dict(),
                    "range": Range((line, col), (line, col)).to_dict(),
                }

        # Could not find a base-64 img embedded, let's see if we have an element
        # with a relative path.
        import re

        p = Path(document.path).parent

        for found in re.findall('"(.+?)"', current_line):
            if found.endswith(".png"):
                check = p / found
                if check.exists():
                    as_uri = uris.from_fs_path(str(check))
                    s = f"![Screenshot]({as_uri})"
                    return {
                        "contents": MarkupContent(MarkupKind.Markdown,
                                                  s).to_dict(),
                        "range": Range((line, col), (line, col)).to_dict(),
                    }

        return None
Exemplo n.º 6
0
    def __init__(self, uri, name, track_file_extensions, fs_observer: IFSObserver):
        self.uri = uri
        self.name = name
        self.path = uris.to_fs_path(uri)

        self._vs: _VirtualFS = _VirtualFS(
            self.path, track_file_extensions, fs_observer=fs_observer
        )
Exemplo n.º 7
0
    def get_interpreter_info_for_doc_uri(self, doc_uri) -> Optional[IInterpreterInfo]:
        try:
            pm = self._pm()
            if pm is None:
                log.critical("Did not expect PluginManager to be None at this point.")
                return None

            from robotframework_ls.ep_providers import (
                EPConfigurationProvider,
                EPEndPointProvider,
            )

            # Check that our requirements are there.
            pm[EPConfigurationProvider]
            pm[EPEndPointProvider]

            fs_path = Path(uris.to_fs_path(doc_uri))
            for path in fs_path.parents:
                robot_yaml: Path = path / "robot.yaml"
                if robot_yaml.exists():
                    break
            else:
                # i.e.: Could not find any robot.yaml in the structure.
                log.debug("Could not find robot.yaml for: %s", fs_path)
                return None

            # Ok, we have the robot_yaml, so, we should be able to run RCC with it.
            robot_yaml_file_info = _CacheInfo.get_file_info(robot_yaml)
            yaml_contents = robot_yaml_file_info.yaml_contents
            if not isinstance(yaml_contents, dict):
                raise AssertionError(f"Expected dict as root in: {robot_yaml}")

            conda_config = yaml_contents.get("condaConfigFile")
            conda_config_file_info = None
            env_json_path_file_info = None

            if conda_config:
                parent: Path = robot_yaml.parent
                conda_config_path = parent / conda_config
                if conda_config_path.exists():
                    conda_config_file_info = _CacheInfo.get_file_info(conda_config_path)

                env_json_path = parent / "devdata" / "env.json"
                if env_json_path.exists():
                    env_json_path_file_info = _CacheInfo.get_file_info(env_json_path)

            return _CacheInfo.get_interpreter_info(
                robot_yaml_file_info,
                conda_config_file_info,
                env_json_path_file_info,
                pm,
            )

        except:
            log.exception(f"Error getting interpreter info for: {doc_uri}")
        return None
Exemplo n.º 8
0
    def __init__(self, uri: str, source=None, version: Optional[str] = None):
        self._main_thread = threading.current_thread()

        self.uri = uri
        self.version = version
        self.path = uris.to_fs_path(uri)  # Note: may be None.

        self._source = source
        self.__line_start_offsets = None

        # Only set when the source is read from disk.
        self._source_mtime = -1
Exemplo n.º 9
0
    def __init__(self, resource_doc):
        """
        :param RobotDocument resource_doc:
        """
        from robocorp_ls_core import uris

        self.keyword_name = ""
        self.resource_doc = resource_doc
        self.source = uris.to_fs_path(resource_doc.uri)
        self.lineno = 1
        self.end_lineno = 1
        self.col_offset = 1
        self.end_col_offset = 1
Exemplo n.º 10
0
    def __init__(self, variables_doc):
        """
        :param RobotDocument variables_doc:
        """
        from robocorp_ls_core import uris

        self.keyword_name = ""
        self.variables_doc = variables_doc
        self.source = uris.to_fs_path(variables_doc.uri)
        # Note: line/offsets 0-based.
        self.lineno = 0
        self.end_lineno = 0
        self.col_offset = 0
        self.end_col_offset = 0
Exemplo n.º 11
0
    def add_workspace_folder(self, folder_uri: str):
        self._check_in_main_thread()
        from robocorp_ls_core import uris

        if folder_uri not in self._workspace_folder_uri_to_folder_info:
            log.debug("Added workspace folder: %s", folder_uri)
            cp = self._workspace_folder_uri_to_folder_info.copy()
            folder_info = cp[folder_uri] = _FolderInfo(
                uris.to_fs_path(folder_uri), recursive=True
            )
            self._workspace_folder_uri_to_folder_info = cp
            folder_info.start_watch(self._observer, self._file_changes_notifier)
            folder_info.synchronize()
        else:
            log.debug("Workspace folder already added: %s", folder_uri)
Exemplo n.º 12
0
    def __init__(self, root_uri, workspace_folders=None) -> None:
        from robocorp_ls_core.lsp import WorkspaceFolder

        self._main_thread = threading.current_thread()

        self._root_uri = root_uri
        self._root_uri_scheme = uri_scheme(self._root_uri)
        self._root_path = to_fs_path(self._root_uri)
        self._folders: Dict[str, WorkspaceFolder] = {}

        # Contains the docs with files considered open.
        self._docs: Dict[str, IDocument] = {}

        # Contains the docs pointing to the filesystem.
        self._filesystem_docs: Dict[str, IDocument] = {}

        if workspace_folders is not None:
            for folder in workspace_folders:
                self.add_folder(folder)

        if root_uri and root_uri not in self._folders:
            as_fs_path = uris.to_fs_path(root_uri)
            name = os.path.basename(as_fs_path)
            self.add_folder(WorkspaceFolder(root_uri, name))
Exemplo n.º 13
0
    def get_resource_import_as_doc(self, resource_import) -> Optional[IRobotDocument]:
        from robocorp_ls_core import uris
        import os.path
        from robotframework_ls.impl.robot_lsp_constants import OPTION_ROBOT_PYTHONPATH

        ws = self._workspace

        for token in resource_import.tokens:
            if token.type == token.NAME:

                name_with_resolved_vars = self.token_value_resolving_variables(
                    token)

                if not os.path.isabs(name_with_resolved_vars):
                    # It's a relative resource, resolve its location based on the
                    # current file.
                    check_paths = [
                        os.path.join(
                            os.path.dirname(
                                self.doc.path), name_with_resolved_vars
                        )
                    ]
                    config = self.config
                    if config is not None:
                        for additional_pythonpath_entry in config.get_setting(
                            OPTION_ROBOT_PYTHONPATH, list, []
                        ):
                            check_paths.append(
                                os.path.join(
                                    os.path.abspath(
                                        os.path.join(os.path.normpath(uris.to_fs_path(ws.root_uri)), additional_pythonpath_entry))
                                    if ws.root_uri is not None and not os.path.isabs(additional_pythonpath_entry) else additional_pythonpath_entry,
                                    name_with_resolved_vars
                                )
                            )

                else:
                    check_paths = [name_with_resolved_vars]

                for resource_path in check_paths:
                    doc_uri = uris.from_fs_path(resource_path)
                    resource_doc = ws.get_document(
                        doc_uri, accept_from_file=True)
                    if resource_doc is None:
                        log.info("Resource not found: %s", resource_path)
                        continue
                    return resource_doc
        return None
def _add_completions_from_dir(
    completion_context,
    directory,
    matcher,
    ret,
    sel,
    token,
    qualifier,
    extensions,
    skip_current,
):
    from robocorp_ls_core import uris

    def normfile(path):
        return os.path.normpath(os.path.normcase(path))

    curr_file = normfile(uris.to_fs_path(completion_context.doc.uri))

    try:
        # This is ok if the directory doesn't exist.
        contents = sorted(os.listdir(directory))
    except:
        return

    for filename in contents:
        use_path = None
        if filename.endswith(extensions):
            # If that'd be a match for the current .robot file, don't show it.
            if skip_current and curr_file == normfile(
                    os.path.join(directory, filename)):
                continue

            use_path = filename

        elif filename not in ("__pycache__", ".git") and os.path.isdir(
                os.path.join(directory, filename)):
            use_path = filename + "/"
        else:
            continue

        if matcher.accepts(use_path):

            ret.append(
                _create_completion_item(use_path,
                                        sel,
                                        token,
                                        start_col_offset=sel.col -
                                        len(qualifier)))
Exemplo n.º 15
0
    def get_interpreter_info_for_doc_uri(self, doc_uri) -> Optional[IInterpreterInfo]:
        as_path = Path(uris.to_fs_path(doc_uri))

        environ = dict(os.environ)

        if as_path.parent.name == "env1":
            return DefaultInterpreterInfo(
                "env1", sys.executable, environ, [str(as_path.parent / "lib1")]
            )

        elif as_path.parent.name == "env2":
            return DefaultInterpreterInfo(
                "env2", sys.executable, environ, [str(as_path.parent / "lib2")]
            )

        return None
Exemplo n.º 16
0
    def _get_library_target_filename(
            self,
            libname: str,
            current_doc_uri: Optional[str] = None) -> Optional[str]:
        from robocorp_ls_core import uris

        target_file: Optional[str] = None
        libname_lower = libname.lower()

        if os.path.isabs(libname):
            target_file = libname
        else:
            # Check if it maps to a file in the filesystem
            if current_doc_uri is not None:
                cwd = os.path.dirname(uris.to_fs_path(current_doc_uri))
                if cwd and os.path.isdir(cwd):
                    f = os.path.join(cwd, libname)
                    if os.path.isdir(f):
                        f = os.path.join(f, "__init__.py")

                    if os.path.exists(f):
                        target_file = f

                    elif not libname_lower.endswith(".py"):
                        f += ".py"
                        if os.path.exists(f):
                            target_file = f

            if target_file is None and libname.endswith(
                (".py", ".class", ".java")):
                iter_in_pythonpath_directories = itertools.chain(
                    self._additional_pythonpath_folder_to_folder_info.keys(),
                    self._pythonpath_folder_to_folder_info.keys(),
                )

                # https://github.com/robocorp/robotframework-lsp/issues/266
                # If the user specifies a file, we don't just search the current
                # relative folder, we also need to search for relative entries
                # in the whole PYTHONPATH.
                for entry in iter_in_pythonpath_directories:
                    check_target = os.path.join(entry, libname)
                    if os.path.exists(check_target):
                        target_file = check_target
                        break

        return target_file
def test_keyword_completions_user_library(
    data_regression, workspace, cases, libspec_manager, library_import, workspace_dir
):
    import os.path
    from robotframework_ls.impl import keyword_completions
    from robotframework_ls.impl.completion_context import CompletionContext
    from robotframework_ls_tests.fixtures import LIBSPEC_1
    from robocorp_ls_core import uris

    cases.copy_to("case1", workspace_dir)

    workspace.set_root(workspace_dir, libspec_manager=libspec_manager)
    doc = workspace.get_doc("case1.robot")

    if library_import == "__FULL_PATH__":
        case1_robot_path = uris.to_fs_path(doc.uri)
        case1_py_path = os.path.join(
            os.path.dirname(case1_robot_path), "case1_library.py"
        )
        library_import = case1_py_path

    doc.source = doc.source.replace(u"case1_library", library_import)
    doc.source = doc.source + u"\n    verify"

    completions = keyword_completions.complete(
        CompletionContext(doc, workspace=workspace.ws)
    )
    data_regression.check(completions, basename="keyword_completions_1")

    # Now, let's put a .libspec file in the workspace and check whether
    # it has priority over the auto-generated spec file.
    with open(os.path.join(workspace_dir, "new_spec.libspec"), "w") as stream:
        stream.write(LIBSPEC_1)
    libspec_manager.synchronize_workspace_folders()

    completions = keyword_completions.complete(
        CompletionContext(doc, workspace=workspace.ws)
    )
    data_regression.check(completions, basename="keyword_completions_2_new")
Exemplo n.º 18
0
def test_server_stdin(setup: _Setup):
    from robocorp_ls_core import uris
    import os

    received_messages = setup.received_messages
    rf_interpreter_server_manager = setup.rf_interpreter_server_manager

    result = rf_interpreter_server_manager.interpreter_start(setup.uri)
    assert result["success"], f"Found: {result}"
    uri = setup.uri
    robot_file = uris.to_fs_path(uri)
    lib_file = os.path.join(os.path.dirname(robot_file), "my_lib.py")
    with open(lib_file, "w", encoding="utf-8") as stream:
        stream.write(r"""
def check_input():
    import sys
    sys.__stdout__.write('Enter something\n')
    return input()
""")
    rf_interpreter_server_manager.interpreter_evaluate(
        "*** Settings ***\nLibrary    ./my_lib.py")

    def check_input_in_thread():
        rf_interpreter_server_manager.interpreter_evaluate("Check Input")

    threading.Thread(target=check_input_in_thread).start()

    def wait_for_enter_something_output():
        for msg in received_messages:
            if (msg["method"] == "interpreter/output"
                    and "Enter something" in msg["params"]["output"]):
                return True
        return False

    wait_for_condition(wait_for_enter_something_output)
    assert rf_interpreter_server_manager._get_api_client().waiting_input
    rf_interpreter_server_manager.interpreter_evaluate("Something\n")
def test_rf_interactive_integrated_fs_completions(
    language_server_io: ILanguageServerClient,
    rf_interpreter_startup: _RfInterpreterInfo,
    data_regression,
):
    from robocorp_ls_core import uris
    from robocorp_ls_core.workspace import Document

    # Check that we're able to get completions based on the current dir.
    from robotframework_ls.commands import ROBOT_INTERNAL_RFINTERACTIVE_COMPLETIONS
    from robocorp_ls_core.lsp import Position

    uri = rf_interpreter_startup.uri
    fs_path = uris.to_fs_path(uri)
    dirname = os.path.dirname(fs_path)
    with open(os.path.join(dirname, "my_lib_03.py"), "w") as stream:
        stream.write("""
def some_method():
    pass
""")

    language_server = language_server_io
    code = "*** Settings ***\nLibrary    ./my_"
    doc = Document(uri, code)
    completions = language_server.execute_command(
        ROBOT_INTERNAL_RFINTERACTIVE_COMPLETIONS,
        [{
            "interpreter_id": rf_interpreter_startup.interpreter_id,
            "code": code,
            "position": Position(*doc.get_last_line_col()).to_dict(),
        }],
    )

    suggestions = completions["result"]["suggestions"]
    assert suggestions
    data_regression.check(suggestions)
Exemplo n.º 20
0
    def add_additional_pythonpath_folder(self, folder_path):
        self._check_in_main_thread()

        from robocorp_ls_core import uris

        if folder_path not in self._additional_pythonpath_folder_to_folder_info:
            log.debug("Added additional pythonpath folder: %s", folder_path)
            cp = self._additional_pythonpath_folder_to_folder_info.copy()

            real_path = os.path.abspath(
                os.path.join(os.path.normpath(uris.to_fs_path(self.root_uri)),
                             folder_path)
            ) if self.root_uri is not None and not os.path.isabs(
                folder_path) else folder_path

            folder_info = cp[folder_path] = _FolderInfo(real_path,
                                                        recursive=True)
            self._additional_pythonpath_folder_to_folder_info = cp
            folder_info.start_watch(self._observer,
                                    self._file_changes_notifier)
            folder_info.synchronize()
        else:
            log.debug("Additional pythonpath folder already added: %s",
                      folder_path)
Exemplo n.º 21
0
def _collect_auto_import_completions(completion_context: ICompletionContext,
                                     collector: _Collector):
    from robotframework_ls.impl.workspace_symbols import iter_symbols_caches
    from robotframework_ls.impl.protocols import ISymbolsCache
    from robocorp_ls_core.protocols import IWorkspace
    from robotframework_ls.robot_config import create_convert_keyword_format_func

    symbols_cache: ISymbolsCache
    selection = completion_context.sel
    token = collector.token

    ws: IWorkspace = completion_context.workspace
    folder_paths = []
    for folder in ws.iter_folders():
        folder_paths.append(uris.to_fs_path(folder.uri))

    curr_doc_path = os.path.dirname(uris.to_fs_path(
        completion_context.doc.uri))

    memo: Set[str] = set()

    default_convert_keyword_format = create_convert_keyword_format_func(
        completion_context.config)
    noop = lambda x: x

    for symbols_cache in iter_symbols_caches(None,
                                             completion_context,
                                             show_builtins=False):
        library_info: Optional[ILibraryDoc] = symbols_cache.get_library_info()
        doc: Optional[IRobotDocument] = symbols_cache.get_doc()

        lib_import = None
        resource_path = None

        if library_info is not None:
            if library_info.source:
                if (library_info.source
                        in collector.import_location_info.imported_libraries):
                    continue
            elif library_info.name in collector.import_location_info.imported_libraries:
                continue

            if library_info.source:
                for folder_path in folder_paths:
                    # If the library is found to be in the workspace, use a relative
                    # path, otherwise use the library name (in which case it's expected
                    # to be in the pythonpath).
                    if library_info.source.startswith(folder_path):
                        try:
                            lib_import = os.path.relpath(
                                library_info.source,
                                curr_doc_path).replace("\\", "/")
                            break
                        except:
                            pass
                else:
                    lib_import = library_info.name

            else:
                lib_import = library_info.name

            convert_keyword_format = default_convert_keyword_format

        elif doc is not None:
            resource_path = doc.path
            try:
                resource_path = os.path.relpath(resource_path,
                                                curr_doc_path).replace(
                                                    "\\", "/")
            except:
                pass
            convert_keyword_format = noop

        json_list = symbols_cache.get_json_list()
        for entry in json_list:
            if collector.accepts(entry):
                collector.create_completion_item(
                    completion_context,
                    convert_keyword_format(entry["name"]),
                    selection,
                    token,
                    0,
                    memo,
                    lib_import=lib_import,
                    resource_path=resource_path,
                    data=None,
                )
Exemplo n.º 22
0
    def _threaded_lint(self, doc_uri, monitor: IMonitor):
        from robocorp_ls_core.jsonrpc.exceptions import JsonRpcRequestCancelled
        from robotframework_ls.impl.robot_lsp_constants import (
            OPTION_ROBOT_LINT_ROBOCOP_ENABLED,
        )
        from robocorp_ls_core import uris

        try:
            from robotframework_ls.impl.ast_utils import collect_errors
            from robotframework_ls.impl import code_analysis
            import os.path

            log.debug("Lint: starting (in thread).")

            completion_context = self._create_completion_context(doc_uri, 0, 0, monitor)
            if completion_context is None:
                return []

            config = completion_context.config
            robocop_enabled = config is None or config.get_setting(
                OPTION_ROBOT_LINT_ROBOCOP_ENABLED, bool, False
            )

            ast = completion_context.get_ast()
            source = completion_context.doc.source
            monitor.check_cancelled()
            errors = collect_errors(ast)
            log.debug("Collected AST errors (in thread): %s", len(errors))
            monitor.check_cancelled()
            analysis_errors = code_analysis.collect_analysis_errors(completion_context)
            monitor.check_cancelled()
            log.debug("Collected analysis errors (in thread): %s", len(analysis_errors))
            errors.extend(analysis_errors)

            lsp_diagnostics = [error.to_lsp_diagnostic() for error in errors]

            try:
                if robocop_enabled:
                    from robocorp_ls_core.robocop_wrapper import (
                        collect_robocop_diagnostics,
                    )

                    workspace = completion_context.workspace
                    if workspace is not None:
                        project_root = workspace.root_path
                    else:
                        project_root = os.path.abspath(".")

                    monitor.check_cancelled()
                    lsp_diagnostics.extend(
                        collect_robocop_diagnostics(
                            project_root, ast, uris.to_fs_path(doc_uri), source
                        )
                    )
            except Exception:
                log.exception(
                    "Error collecting Robocop errors (possibly an unsupported Robocop version is installed)."
                )

            return lsp_diagnostics
        except JsonRpcRequestCancelled:
            raise JsonRpcRequestCancelled("Lint cancelled (inside lint)")
        except:
            log.exception("Error collecting errors.")
            return []
Exemplo n.º 23
0
        def run():
            from robotframework_ls import import_rf_interactive
            from robotframework_ls.config_extension import (
                apply_interpreter_info_to_config,
            )
            from robocorp_ls_core.ep_resolve_interpreter import EPResolveInterpreter
            from robocorp_ls_core import uris

            import_rf_interactive()

            from robocorp_ls_core.options import Setup

            try:
                from robotframework_interactive.server.rf_interpreter_server_manager import (
                    RfInterpreterServerManager,
                )

                interpreter_id = self._next_interpreter_id()

                def on_interpreter_message(interpreter_message: dict):
                    """
                    :param interpreter_message:
                    Something as:
                    {
                        "jsonrpc": "2.0",
                        "method": "interpreter/output",
                        "params": {
                            "output": "Some output\n",
                            "category": "stdout",
                        },
                    }
                    """

                    params = interpreter_message["params"]
                    params["interpreter_id"] = interpreter_id
                    self._endpoint.notify(interpreter_message["method"], params)

                rf_interpreter_server_manager = RfInterpreterServerManager(
                    verbose=Setup.options.verbose,
                    base_log_file=Setup.options.log_file,
                    on_interpreter_message=on_interpreter_message,
                    uri=uri,
                )
                fs_path = uris.to_fs_path(uri)
                rf_interpreter_server_manager.config = config
                rf_config = rf_interpreter_server_manager.config

                # Just making sure that it has its own private copy before
                # mutating it...
                assert rf_config is not config

                for ep in self._pm.get_implementations(EPResolveInterpreter):
                    interpreter_info = ep.get_interpreter_info_for_doc_uri(uri)
                    if interpreter_info is not None:
                        on_interpreter_message(
                            {
                                "jsonrpc": "2.0",
                                "method": "interpreter/output",
                                "params": {
                                    "output": f"Target: {interpreter_info.get_interpreter_id()}\n",
                                    "category": "info",
                                },
                            }
                        )
                        apply_interpreter_info_to_config(rf_config, interpreter_info)
                        break

                on_interpreter_message(
                    {
                        "jsonrpc": "2.0",
                        "method": "interpreter/output",
                        "params": {"output": f"Path: {fs_path}\n", "category": "info"},
                    }
                )
                rf_interpreter_server_manager.interpreter_start(uri)
                ls_thread_pool = futures.ThreadPoolExecutor(max_workers=2)
                self._interpreter_id_to_rf_info[interpreter_id] = _RfInfo(
                    rf_interpreter_server_manager, commands_thread_pool, ls_thread_pool
                )

            except Exception as e:
                log.exception("Error starting interpreter.")
                return ActionResult(False, message=str(e)).as_dict()
            else:
                return ActionResult(
                    True, result={"interpreter_id": interpreter_id}
                ).as_dict()
Exemplo n.º 24
0
def test_win_to_fs_path(uri, path):
    assert uris.to_fs_path(uri) == path
def _get_completions(completion_context, token, match_libs, extensions,
                     skip_current):
    from robotframework_ls.impl.string_matcher import RobotStringMatcher
    from robocorp_ls_core import uris
    from robotframework_ls.impl.robot_constants import BUILTIN_LIB, RESERVED_LIB

    ret = []

    sel = completion_context.sel
    value_to_cursor = token.value
    if token.end_col_offset > sel.col:
        value_to_cursor = value_to_cursor[:-(token.end_col_offset - sel.col)]
    if "{" in value_to_cursor:
        value_to_cursor = completion_context.token_value_resolving_variables(
            value_to_cursor)

    value_to_cursor_split = os.path.split(value_to_cursor)

    if os.path.isabs(value_to_cursor):
        _add_completions_from_dir(
            completion_context,
            value_to_cursor_split[0],
            RobotStringMatcher(value_to_cursor_split[1]),
            ret,
            sel,
            token,
            value_to_cursor_split[1],
            extensions,
            skip_current=skip_current,
        )

    else:
        if match_libs:
            matcher = RobotStringMatcher(value_to_cursor)
            libspec_manager = completion_context.workspace.libspec_manager
            library_names = set(libspec_manager.get_library_names())
            library_names.discard(BUILTIN_LIB)
            library_names.discard(RESERVED_LIB)

            for library_name in library_names:
                if matcher.accepts(library_name):
                    ret.append(
                        _create_completion_item(library_name, sel, token))

        # After checking the existing library names in memory (because we
        # loaded them at least once), check libraries in the filesystem.
        uri = completion_context.doc.uri
        path = uris.to_fs_path(uri)
        dirname = os.path.dirname(path)

        matcher = RobotStringMatcher(value_to_cursor_split[1])
        directory = os.path.join(dirname, value_to_cursor_split[0])
        _add_completions_from_dir(
            completion_context,
            directory,
            matcher,
            ret,
            sel,
            token,
            value_to_cursor_split[1],
            extensions,
            skip_current=skip_current,
        )
    return ret
def test_rf_interactive_integrated_input_request(
    language_server_io: ILanguageServerClient,
    rf_interpreter_startup: _RfInterpreterInfo,
):
    from robotframework_ls.commands import ROBOT_INTERNAL_RFINTERACTIVE_EVALUATE
    from robocorp_ls_core import uris

    language_server = language_server_io
    uri = rf_interpreter_startup.uri
    robot_file = uris.to_fs_path(uri)
    lib_file = os.path.join(os.path.dirname(robot_file), "my_lib.py")
    with open(lib_file, "w", encoding="utf-8") as stream:
        stream.write(r"""
def check_input():
    import sys
    sys.__stdout__.write('Enter something\n')
    return input()
""")

    message_matcher = language_server.obtain_pattern_message_matcher(
        {"method": "interpreter/output"})
    language_server.execute_command(
        ROBOT_INTERNAL_RFINTERACTIVE_EVALUATE,
        [{
            "interpreter_id": 0,
            "code": "*** Settings ***\nLibrary    ./my_lib.py"
        }],
    )

    def run_in_thread():
        language_server.execute_command(
            ROBOT_INTERNAL_RFINTERACTIVE_EVALUATE,
            [{
                "interpreter_id":
                0,
                "code":
                """
*** Test Case ***
Test
    ${var}=  Check Input
    Log    ${var}     console=True
""",
            }],
        )

    t = threading.Thread(target=run_in_thread)
    t.start()

    assert message_matcher.event.wait(10)
    assert message_matcher.msg == {
        "jsonrpc": "2.0",
        "method": "interpreter/output",
        "params": {
            "output": "Enter something\n",
            "category": "stdout",
            "interpreter_id": 0,
        },
    }
    import time

    time.sleep(0.5)

    message_matcher = language_server.obtain_pattern_message_matcher(
        {"method": "interpreter/output"})

    language_server.execute_command(
        ROBOT_INTERNAL_RFINTERACTIVE_EVALUATE,
        [{
            "interpreter_id": 0,
            "code": "EnterThis"
        }],
    )
    assert message_matcher.event.wait(10)
    assert message_matcher.msg == {
        "jsonrpc": "2.0",
        "method": "interpreter/output",
        "params": {
            "output": "EnterThis\n",
            "category": "stdout",
            "interpreter_id": 0
        },
    }

    t.join(10)
    assert not t.is_alive()
Exemplo n.º 27
0
    def resource_name(self):
        from robocorp_ls_core import uris

        uri = self.completion_context.doc.uri
        return os.path.splitext(os.path.basename(uris.to_fs_path(uri)))[0]
Exemplo n.º 28
0
 def get_folder_paths(self) -> List[str]:
     folders = self._folders  # Ok, thread-safe (folders are always set as a whole)
     return [
         uris.to_fs_path(ws_folder.uri) for ws_folder in folders.values()
     ]
Exemplo n.º 29
0
    def source(self):
        from robocorp_ls_core import uris

        return uris.to_fs_path(self.completion_context.doc.uri)
    def lint(self, doc_uri, is_saved):
        from robocorp_ls_core.lsp import DiagnosticSeverity
        from robocorp_ls_core import uris
        import json

        if is_saved:
            # When a documnt is saved, if it's a conda.yaml or a robot.yaml,
            # validate it.
            if doc_uri.endswith("conda.yaml") or doc_uri.endswith(
                    "robot.yaml"):
                robot_yaml_fs_path = uris.to_fs_path(doc_uri)
                if robot_yaml_fs_path.endswith("conda.yaml"):
                    p = os.path.dirname(robot_yaml_fs_path)
                    for _ in range(3):
                        target = os.path.join(p, "robot.yaml")
                        if target and os.path.exists(target):
                            robot_yaml_fs_path = target
                            break
                    else:
                        # We didn't find the 'robot.yaml' for the 'conda.yaml'
                        # bail out.
                        return

                action_result = self._rcc.configuration_diagnostics(
                    robot_yaml_fs_path)
                if action_result.success:
                    json_contents = action_result.result
                    as_dict = json.loads(json_contents)
                    checks = as_dict.get("checks", [])
                    found = []
                    if isinstance(checks, (list, tuple)):
                        for check in checks:
                            if isinstance(check, dict):
                                status = check.get("status", "ok").lower()
                                if status != "ok":

                                    # Default is error (for fail/fatal)
                                    severity = DiagnosticSeverity.Error

                                    if status in ("warn", "warning"):
                                        severity = DiagnosticSeverity.Warning
                                    elif status in ("info", "information"):
                                        severity = DiagnosticSeverity.Information

                                    # The actual line is not given by rcc, so, put
                                    # all errors in the first 2 lines.
                                    message = check.get(
                                        "message",
                                        "<unable to get error message>")

                                    url = check.get("url")
                                    if url:
                                        message += (
                                            f" -- see: {url} for more information."
                                        )
                                    found.append({
                                        "range": {
                                            "start": {
                                                "line": 0,
                                                "character": 0
                                            },
                                            "end": {
                                                "line": 1,
                                                "character": 0
                                            },
                                        },
                                        "severity": severity,
                                        "source": "robocorp-code",
                                        "message": message,
                                    })
                    self._lsp_messages.publish_diagnostics(doc_uri, found)