예제 #1
0
def test_keyword_completions_respect_pythonpath(workspace, cases,
                                                libspec_manager,
                                                data_regression):
    from robotframework_ls.impl import keyword_completions
    from robotframework_ls.impl.completion_context import CompletionContext
    from robocode_ls_core.config import Config
    from robotframework_ls.impl.robot_lsp_constants import OPTION_ROBOT_PYTHONPATH

    case4_path = cases.get_path("case4")

    # Note how we are accessing case4resource.txt while the workspace is set for case3.

    config = Config(root_uri="", init_opts={}, process_id=-1, capabilities={})
    config.update({"robot": {"pythonpath": [case4_path]}})
    assert config.get_setting(OPTION_ROBOT_PYTHONPATH, list,
                              []) == [case4_path]
    libspec_manager.config = config

    workspace.set_root(cases.get_path("case3"),
                       libspec_manager=libspec_manager)
    doc = workspace.get_doc("case3.robot")
    doc.source = """*** Settings ***
Resource    case4resource.txt

*** Test Cases ***
Can use resource keywords
    [Documentation]      Checks that we can have a resource
    ...                  including another resource.
    My Equal Redefined   2   2
    Yet Another Equ"""

    completions = keyword_completions.complete(
        CompletionContext(doc, workspace=workspace.ws, config=config))

    data_regression.check(completions)
예제 #2
0
def test_keyword_completions_from_resource_files(data_regression, workspace,
                                                 tmpdir, cases,
                                                 libspec_manager):
    from robotframework_ls.impl import keyword_completions
    from robotframework_ls.impl.completion_context import CompletionContext
    from robotframework_ls.impl.robot_lsp_constants import OPTION_ROBOT_VARIABLES
    from robocode_ls_core.config import Config

    config = Config(root_uri="", init_opts={}, process_id=-1, capabilities={})
    config.update(
        {"robot": {
            "variables": {
                "ext_folder": cases.get_path("ext")
            }
        }})
    assert config.get_setting(OPTION_ROBOT_VARIABLES, dict, {}) == {
        "ext_folder": cases.get_path("ext")
    }

    workspace.set_root(cases.get_path("case3"),
                       libspec_manager=libspec_manager)
    doc = workspace.get_doc("case3.robot")
    doc.source = doc.source + "\n    equal redef"

    completions = keyword_completions.complete(
        CompletionContext(doc, workspace=workspace.ws, config=config))
    data_regression.check(completions,
                          basename="keyword_completions_from_resource_files")
예제 #3
0
def test_resource_does_not_exist(workspace, libspec_manager, data_regression):
    workspace.set_root("case4", libspec_manager=libspec_manager)
    doc = workspace.get_doc("case4.robot")

    doc.source = """*** Settings ***
Library    DoesNotExist
Library    .
Library    ..
Library    ../
Resource    does_not_exist.txt
Resource    ${foo}/does_not_exist.txt
Resource    ../does_not_exist.txt
Resource    .
Resource    ..
Resource    ../
Resource    ../../does_not_exist.txt
Resource    case4resource.txt

*** Test Cases ***
Test
    case4resource3.Yet Another Equal Redefined"""

    from robocode_ls_core.config import Config

    config = Config(root_uri="", init_opts={}, process_id=-1, capabilities={})
    # Note: we don't give errors if we can't resolve a resource.
    _collect_errors(workspace,
                    doc,
                    data_regression,
                    basename="no_error",
                    config=config)
예제 #4
0
def test_keyword_completions_resource_does_not_exist(workspace,
                                                     libspec_manager,
                                                     data_regression):
    from robocode_ls_core.config import Config
    from robotframework_ls.impl import keyword_completions
    from robotframework_ls.impl.completion_context import CompletionContext

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

    doc.source = """*** Settings ***
Library    DoesNotExist
Library    .
Library    ..
Library    ../
Resource    does_not_exist.txt
Resource    ${foo}/does_not_exist.txt
Resource    ../does_not_exist.txt
Resource    .
Resource    ..
Resource    ../
Resource    ../../does_not_exist.txt
Resource    case4resource.txt

*** Test Cases ***
Test
    case4resource3."""

    config = Config(root_uri="", init_opts={}, process_id=-1, capabilities={})
    completions = keyword_completions.complete(
        CompletionContext(doc, workspace=workspace.ws, config=config))

    data_regression.check(completions)
예제 #5
0
    def m_initialize(
        self,
        processId=None,
        rootUri=None,
        rootPath=None,
        initializationOptions=None,
        workspaceFolders=None,
        **_kwargs
    ):
        from robocode_ls_core.basic import exit_when_pid_exists
        from robocode_ls_core.lsp import WorkspaceFolder
        from robocode_ls_core.config import Config

        log.debug(
            "Language server initialized with:\n    processId: %s\n    rootUri: %s\n    rootPath: %s\n    initializationOptions: %s\n    workspaceFolders: %s",
            processId,
            rootUri,
            rootPath,
            initializationOptions,
            workspaceFolders,
        )
        if rootUri is None:
            rootUri = uris.from_fs_path(rootPath) if rootPath is not None else ""

        self.root_uri = rootUri
        self.config = Config(
            rootUri,
            initializationOptions or {},
            processId,
            _kwargs.get("capabilities", {}),
        )
        if workspaceFolders:
            workspaceFolders = [WorkspaceFolder(**w) for w in workspaceFolders]

        self.workspace = self._create_workspace(rootUri, workspaceFolders or [])

        if processId not in (None, -1, 0):
            exit_when_pid_exists(processId)

        # Get our capabilities
        return {"capabilities": self.capabilities()}
예제 #6
0
def test_section_completions(data_regression):
    from robotframework_ls.impl import section_completions
    from robotframework_ls.impl.completion_context import CompletionContext
    from robotframework_ls.impl.robot_workspace import RobotDocument
    from robocode_ls_core.config import Config

    config = Config(root_uri="", init_opts={}, process_id=-1, capabilities={})
    config.update({"robot": {"completions": {"section_headers": {"form": "both"}}}})

    doc = RobotDocument("unused", source="""**""")
    completions = section_completions.complete(CompletionContext(doc, config=config))
    data_regression.check(completions, basename="header_completions_all")

    doc = RobotDocument("unused", source="""**settin""")
    completions = section_completions.complete(CompletionContext(doc, config=config))
    data_regression.check(completions, basename="header_completions_filter_settings")

    config.update({})
    doc = RobotDocument("unused", source="""**""")
    completions = section_completions.complete(CompletionContext(doc, config=config))
    data_regression.check(completions, basename="header_completions_all_plural")
예제 #7
0
    def _create_config(self) -> IConfig:
        from robocode_ls_core.config import Config

        return Config(all_options=frozenset())
예제 #8
0
def test_config(tmpdir):
    from robotframework_ls.impl.robot_lsp_constants import (
        OPTION_ROBOT_PYTHON_EXECUTABLE, )
    from robocode_ls_core.config import Config
    from robotframework_ls.impl.robot_lsp_constants import (
        OPTION_ROBOT_LANGUAGE_SERVER_TCP_PORT, )

    config = Config(root_uri=str(tmpdir),
                    init_opts={},
                    process_id=None,
                    capabilities={})
    settings = {
        "robot": {
            "language-server": {
                "tcp-port": 1456,
                "args": ["-vv", "--log-file=~/robotframework_ls.log"],
            },
            "python": {
                "executable": "foobar",
                "value": "10",
                "value_float": "10.5"
            },
        }
    }
    config.update(settings)
    assert config.get_setting(OPTION_ROBOT_PYTHON_EXECUTABLE, str) == "foobar"
    assert config.get_setting(OPTION_ROBOT_LANGUAGE_SERVER_TCP_PORT,
                              int) == 1456

    # i.e.: convert to type when possible
    assert config.get_setting("robot.python.value", int) == 10
    assert config.get_setting("robot.python.value_float", float) == 10.5

    with pytest.raises(KeyError):
        config.get_setting("robot.python.value_float", int)

    with pytest.raises(KeyError):
        assert config.get_setting("robot.not_there", int)
예제 #9
0
class PythonLanguageServer(MethodDispatcher):
    """ Implementation of the Microsoft VSCode Language Server Protocol
    https://github.com/Microsoft/language-server-protocol/blob/master/versions/protocol-1-x.md
    
    Based on: https://github.com/palantir/python-language-server/blob/develop/pyls/python_ls.py
    """

    def __init__(self, read_stream, write_stream, max_workers=MAX_WORKERS):
        from robocode_ls_core.lsp import LSPMessages

        self.workspace = None
        self.config = None
        self.root_uri = None
        self.watching_thread = None
        self.uri_workspace_mapper = {}

        self._jsonrpc_stream_reader = JsonRpcStreamReader(read_stream)
        self._jsonrpc_stream_writer = JsonRpcStreamWriter(write_stream)
        self._endpoint = Endpoint(
            self, self._jsonrpc_stream_writer.write, max_workers=max_workers
        )
        self._lsp_messages = LSPMessages(self._endpoint)

        self._shutdown = False

    def start(self):
        """Entry point for the server."""
        self._jsonrpc_stream_reader.listen(self._endpoint.consume)

    def m_shutdown(self, **_kwargs):
        self._shutdown = True
        return None

    def m_exit(self, **_kwargs):
        self._endpoint.shutdown()
        # If there's someone reading, we could deadlock here.
        self._jsonrpc_stream_reader.close()
        self._jsonrpc_stream_writer.close()

    def capabilities(self):
        return {}  # Subclasses should override for capabilities.

    def m_initialize(
        self,
        processId=None,
        rootUri=None,
        rootPath=None,
        initializationOptions=None,
        workspaceFolders=None,
        **_kwargs
    ):
        from robocode_ls_core.basic import exit_when_pid_exists
        from robocode_ls_core.lsp import WorkspaceFolder
        from robocode_ls_core.config import Config

        log.debug(
            "Language server initialized with:\n    processId: %s\n    rootUri: %s\n    rootPath: %s\n    initializationOptions: %s\n    workspaceFolders: %s",
            processId,
            rootUri,
            rootPath,
            initializationOptions,
            workspaceFolders,
        )
        if rootUri is None:
            rootUri = uris.from_fs_path(rootPath) if rootPath is not None else ""

        self.root_uri = rootUri
        self.config = Config(
            rootUri,
            initializationOptions or {},
            processId,
            _kwargs.get("capabilities", {}),
        )
        if workspaceFolders:
            workspaceFolders = [WorkspaceFolder(**w) for w in workspaceFolders]

        self.workspace = self._create_workspace(rootUri, workspaceFolders or [])

        if processId not in (None, -1, 0):
            exit_when_pid_exists(processId)

        # Get our capabilities
        return {"capabilities": self.capabilities()}

    def _create_workspace(self, root_uri, workspace_folders):
        from robocode_ls_core.workspace import Workspace

        return Workspace(root_uri, workspace_folders)

    def m_initialized(self, **_kwargs):
        pass

    def lint(self, doc_uri, is_saved):
        raise NotImplementedError(
            "Subclasses must override (current class: %s)." % (self.__class__,)
        )

    def m_text_document__did_close(self, textDocument=None, **_kwargs):
        self.workspace.remove_document(textDocument["uri"])

    def m_text_document__did_open(self, textDocument=None, **_kwargs):
        from robocode_ls_core.lsp import TextDocumentItem

        self.workspace.put_document(TextDocumentItem(**textDocument))
        self.lint(textDocument["uri"], is_saved=True)

    def m_text_document__did_change(
        self, contentChanges=None, textDocument=None, **_kwargs
    ):
        from robocode_ls_core.lsp import TextDocumentItem
        from robocode_ls_core.lsp import TextDocumentContentChangeEvent

        if contentChanges:
            text_document_item = TextDocumentItem(**textDocument)
            for change in contentChanges:
                try:
                    range = change.get("range", None)
                    range_length = change.get("rangeLength", 0)
                    text = change.get("text", "")
                    self.workspace.update_document(
                        text_document_item,
                        TextDocumentContentChangeEvent(
                            range=range, rangeLength=range_length, text=text
                        ),
                    )
                except:
                    log.exception(
                        "Error updating document: %s with changes: %s"
                        % (textDocument, contentChanges)
                    )
        self.lint(textDocument["uri"], is_saved=False)

    def m_text_document__did_save(self, textDocument=None, **_kwargs):
        self.lint(textDocument["uri"], is_saved=True)

    def m_workspace__did_change_configuration(self, settings=None):
        self.config.update(settings or {})

    def m_workspace__did_change_workspace_folders(self, event):
        """Adds/Removes folders from the workspace."""
        from robocode_ls_core.lsp import WorkspaceFolder

        log.info("Workspace folders changed: {}".format(event))

        added_folders = event["added"] or []
        removed_folders = event["removed"] or []

        for f_add in added_folders:
            self.workspace.add_folder(WorkspaceFolder(**f_add))

        for f_remove in removed_folders:
            self.workspace.remove_folder(f_remove["uri"])

    def m_workspace__did_change_watched_files(self, changes=None, **_kwargs):
        pass