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
예제 #2
0
 def visit_TestCase(self, node: TestCase):
     self.code_lens.append(
         CodeLens(
             Range(Position(node.header.lineno - 1, node.header.col_offset),
                   Position(node.header.lineno - 1,
                            node.header.col_offset)),
             Command("Run Test", "robot.runTestcase",
                     [self.doc_uri, node.name])))
     self.code_lens.append(
         CodeLens(
             Range(Position(node.header.lineno - 1, node.header.col_offset),
                   Position(node.header.lineno - 1,
                            node.header.col_offset)),
             Command("Debug Test", "robot.debugTestcase",
                     [self.doc_uri, node.name])))
예제 #3
0
def code_lens(completion_context: ICompletionContext,
              doc_uri: str) -> Optional[List[Dict]]:
    result = []

    result.append(
        CodeLens(Range(Position(0, 0), Position(0, 0)),
                 Command("Run Suite", "robot.runTestsuite", [doc_uri])))
    result.append(
        CodeLens(Range(Position(0, 0), Position(0, 0)),
                 Command("Debug Suite", "robot.debugTestsuite", [doc_uri])))

    result += CodeLensVisitor.find_from(completion_context.get_ast(), doc_uri,
                                        completion_context)

    return list([x.to_dict() for x in result])
예제 #4
0
def complete(completion_context):
    """
    :param CompletionContext completion_context:
    """
    from robocorp_ls_core.lsp import CompletionItemKind
    from robocorp_ls_core.lsp import CompletionItem
    from robocorp_ls_core.lsp import TextEdit
    from robocorp_ls_core.lsp import Range
    from robocorp_ls_core.lsp import Position
    from robotframework_ls.impl import text_utilities
    from robotframework_ls.impl.string_matcher import RobotStringMatcher
    from robotframework_ls.impl.robot_lsp_constants import (
        OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM, )
    from robotframework_ls.impl.robot_lsp_constants import (
        OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM_PLURAL, )

    selection = completion_context.sel  #: :type selection: DocumentSelection
    line_start = selection.line_to_column
    items = []

    if line_start:
        tu = text_utilities.TextUtilities(line_start)

        if tu.strip_leading_chars("*"):  # i.e.: the line must start with '*'
            tu.strip()

            words = completion_context.get_accepted_section_header_words()
            config = completion_context.config

            form = config.get_setting(
                OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM,
                str,
                OPTION_ROBOT_COMPLETION_SECTION_HEADERS_FORM_PLURAL,
            )
            matcher = RobotStringMatcher(tu.text)
            for word in words:
                if form == "plural":
                    if not word.endswith("s"):
                        continue
                elif form == "singular":
                    if word.endswith("s"):
                        continue
                if matcher.accepts(word):
                    label = "*** %s ***" % (word, )
                    text_edit = TextEdit(
                        Range(
                            # i.e.: always replace from the start of the line.
                            start=Position(selection.line, 0),
                            end=Position(selection.line, selection.col),
                        ),
                        label,
                    )
                    # text_edit = None
                    items.append(
                        CompletionItem(label,
                                       kind=CompletionItemKind.Class,
                                       text_edit=text_edit,
                                       insertText=text_edit.newText))

    return [item.to_dict() for item in items]
def _create_completion_item(
    label: str,
    new_text: str,
    selection: IDocumentSelection,
    col_start: int,
    col_end: int,
    documentation: str,
) -> dict:
    from robocorp_ls_core.lsp import (
        CompletionItem,
        InsertTextFormat,
        Position,
        Range,
        TextEdit,
    )
    from robocorp_ls_core.lsp import MarkupKind
    from robocorp_ls_core.lsp import CompletionItemKind

    text_edit = TextEdit(
        Range(
            start=Position(selection.line, col_start),
            end=Position(selection.line, col_end),
        ),
        new_text,
    )

    return CompletionItem(
        label,
        kind=CompletionItemKind.Field,
        text_edit=text_edit,
        insertText=label,
        documentation=documentation,
        insertTextFormat=InsertTextFormat.PlainText,
        documentationFormat=MarkupKind.PlainText,
    ).to_dict()
예제 #6
0
def test_document_multiline_edit():
    old = ["def hello(a, b):\n", "    print a\n", "    print b\n"]
    doc = Document("file:///uri", u"".join(old))
    change = TextDocumentContentChangeEvent(
        Range(Position(1, 4), Position(2, 11)), 0, u"print a, b")
    doc.apply_change(change)

    assert doc.get_internal_lines() == ("def hello(a, b):\n",
                                        "    print a, b\n")
예제 #7
0
def test_document_end_of_file_edit():
    old = ["print 'a'\n", "print 'b'\n"]
    doc = Document("file:///uri", u"".join(old))

    change = TextDocumentContentChangeEvent(
        Range(Position(2, 0), Position(2, 0)), 0, u"o")
    doc.apply_change(change)

    assert doc.get_internal_lines() == ("print 'a'\n", "print 'b'\n", "o")
예제 #8
0
    def _create_completion_item_from_keyword(self,
                                             keyword_found: IKeywordFound,
                                             selection,
                                             token,
                                             col_delta=0):
        from robocorp_ls_core.lsp import (
            CompletionItem,
            InsertTextFormat,
            Position,
            Range,
            TextEdit,
        )
        from robocorp_ls_core.lsp import MarkupKind
        from robotframework_ls.impl.protocols import IKeywordArg

        label = keyword_found.keyword_name

        if keyword_found.library_name:
            # If we found the keyword in a library, convert its format depending on
            # the user configuration.
            label = self._convert_keyword_format(label)

        text = label
        arg: IKeywordArg
        for i, arg in enumerate(keyword_found.keyword_args):
            if arg.is_keyword_arg or arg.is_star_arg or arg.default_value is not None:
                continue

            arg_name = arg.arg_name
            arg_name = arg_name.replace("$",
                                        "\\$").replace("{",
                                                       "").replace("}", "")

            text += "    ${%s:%s}" % (i + 1, arg_name)

        text_edit = TextEdit(
            Range(
                start=Position(selection.line, token.col_offset + col_delta),
                end=Position(selection.line, token.end_col_offset),
            ),
            text,
        )

        # text_edit = None
        return CompletionItem(
            label,
            kind=keyword_found.completion_item_kind,
            text_edit=text_edit,
            insertText=text_edit.newText,
            documentation=keyword_found.docs,
            insertTextFormat=InsertTextFormat.Snippet,
            documentationFormat=(MarkupKind.Markdown
                                 if keyword_found.docs_format == "markdown"
                                 else MarkupKind.PlainText),
        ).to_dict()
    def _create_completion_item_from_keyword(self,
                                             keyword_found: IKeywordFound,
                                             selection,
                                             token,
                                             col_delta=0):
        from robocorp_ls_core.lsp import (
            CompletionItem,
            InsertTextFormat,
            Position,
            Range,
            TextEdit,
        )
        from robocorp_ls_core.lsp import MarkupKind
        from robotframework_ls.impl.robot_specbuilder import KeywordArg

        label = keyword_found.keyword_name
        text = label

        arg: KeywordArg
        for i, arg in enumerate(keyword_found.keyword_args):
            if arg.is_keyword_arg or arg.is_star_arg or arg.default_value is not None:
                continue

            arg_name = arg.arg_name
            arg_name = arg_name.replace("$",
                                        "\\$").replace("{",
                                                       "").replace("}", "")

            text += "    ${%s:%s}" % (i + 1, arg_name)

        text_edit = TextEdit(
            Range(
                start=Position(
                    selection.line, token.col_offset +
                    col_delta if token is not None else selection.col),
                end=Position(
                    selection.line, token.end_col_offset
                    if token is not None else selection.col),
            ),
            text,
        )

        # text_edit = None
        return CompletionItem(
            keyword_found.keyword_name,
            kind=keyword_found.completion_item_kind,
            text_edit=text_edit,
            insertText=text_edit.newText,
            documentation=keyword_found.docs,
            insertTextFormat=InsertTextFormat.Snippet,
            documentationFormat=(MarkupKind.Markdown
                                 if keyword_found.docs_format == "markdown"
                                 else MarkupKind.PlainText),
        )
예제 #10
0
    def _threaded_find_definition(self, doc_uri, line, col, monitor) -> Optional[list]:
        from robotframework_ls.impl.find_definition import find_definition
        import os.path
        from robocorp_ls_core.lsp import Location, Range
        from robocorp_ls_core import uris

        completion_context = self._create_completion_context(
            doc_uri, line, col, monitor
        )
        if completion_context is None:
            return None
        definitions = find_definition(completion_context)
        ret = []
        for definition in definitions:
            if not definition.source:
                log.info("Found definition with empty source (%s).", definition)
                continue

            if not os.path.exists(definition.source):
                log.info(
                    "Found definition: %s (but source does not exist).", definition
                )
                continue

            lineno = definition.lineno
            if lineno is None or lineno < 0:
                lineno = 0

            end_lineno = definition.end_lineno
            if end_lineno is None or end_lineno < 0:
                end_lineno = 0

            col_offset = definition.col_offset
            end_col_offset = definition.end_col_offset

            ret.append(
                Location(
                    uris.from_fs_path(definition.source),
                    Range((lineno, col_offset), (end_lineno, end_col_offset)),
                ).to_dict()
            )
        return ret
예제 #11
0
    def _create_completion_item_from_variable(self, variable_found, selection,
                                              token):
        """
        :param IVariableFound variable_found:
        :param selection:
        :param token:
        """
        from robocorp_ls_core.lsp import (
            CompletionItem,
            InsertTextFormat,
            Position,
            Range,
            TextEdit,
        )
        from robocorp_ls_core.lsp import MarkupKind
        from robocorp_ls_core.lsp import CompletionItemKind

        label = variable_found.variable_name
        text = label
        text = text.replace("$", "\\$")

        text_edit = TextEdit(
            Range(
                start=Position(selection.line, token.col_offset),
                end=Position(selection.line, token.end_col_offset),
            ),
            text,
        )

        # text_edit = None
        return CompletionItem(
            variable_found.variable_name,
            kind=CompletionItemKind.Variable,
            text_edit=text_edit,
            insertText=label,
            documentation=variable_found.variable_value,
            insertTextFormat=InsertTextFormat.Snippet,
            documentationFormat=MarkupKind.PlainText,
        ).to_dict()
def _create_completion_item_from_snippet(label, snippet, selection,
                                         line_to_col):
    """
    :param selection: DocumentSelection
    """
    from robocorp_ls_core.lsp import (
        CompletionItem,
        InsertTextFormat,
        Position,
        Range,
        TextEdit,
    )
    from robocorp_ls_core.lsp import MarkupKind
    from robocorp_ls_core.lsp import CompletionItemKind

    current_col = selection.col

    text = "\n".join(snippet["body"])

    text_edit = TextEdit(
        Range(
            start=Position(selection.line, current_col - len(line_to_col)),
            end=Position(selection.line, current_col),
        ),
        text,
    )

    return CompletionItem(
        label,
        kind=CompletionItemKind.Snippet,
        text_edit=text_edit,
        insertText=text_edit.newText,
        documentation=snippet["description"] +
        "\n".join(["", ""] + snippet["body"]),
        insertTextFormat=InsertTextFormat.Snippet,
        documentationFormat=MarkupKind.Markdown,
    ).to_dict()
def _create_completion_item(library_name,
                            selection,
                            token,
                            start_col_offset=None):
    from robocorp_ls_core.lsp import (
        CompletionItem,
        InsertTextFormat,
        Position,
        Range,
        TextEdit,
    )
    from robocorp_ls_core.lsp import MarkupKind
    from robocorp_ls_core.lsp import CompletionItemKind

    text_edit = TextEdit(
        Range(
            start=Position(
                selection.line,
                start_col_offset
                if start_col_offset is not None else token.col_offset,
            ),
            end=Position(selection.line, token.end_col_offset),
        ),
        library_name,
    )

    # text_edit = None
    return CompletionItem(
        library_name,
        kind=CompletionItemKind.Module,
        text_edit=text_edit,
        insertText=text_edit.newText,
        documentation="",
        insertTextFormat=InsertTextFormat.Snippet,
        documentationFormat=MarkupKind.PlainText,
    ).to_dict()
예제 #14
0
def test_document_empty_edit():
    doc = Document("file:///uri", u"")
    change = TextDocumentContentChangeEvent(
        Range(Position(0, 0), Position(0, 0)), 0, u"f")
    doc.apply_change(change)
    assert doc.source == u"f"
예제 #15
0
    def create_completion_item(
        self,
        completion_context: ICompletionContext,
        keyword_name,
        selection,
        token,
        col_delta: int,
        memo: Set[str],
        lib_import: Optional[str] = None,
        resource_path: Optional[str] = None,
        data: Optional[Any] = None,
    ) -> None:
        """
        Note: the lib_import and resource_path are the strings to be added
        so that the given library/resource is loaded.
        
        i.e.: It's the name concatenated to the `Library    {lib_import}` or
        `Resource    {resource_path}`.
        """
        from robocorp_ls_core.lsp import (
            CompletionItem,
            InsertTextFormat,
            Position,
            Range,
            TextEdit,
        )
        from robocorp_ls_core.lsp import MarkupKind
        from robotframework_ls.impl.protocols import CompletionType

        label = f"{keyword_name} ({lib_import or resource_path})"
        if label in memo:
            return
        memo.add(label)

        prefix = ""
        import_line = -1
        if completion_context.type != CompletionType.shell:
            if lib_import is not None:
                import_line = self.import_location_info.get_library_import_line(
                )
            elif resource_path is not None:
                import_line = self.import_location_info.get_resource_import_line(
                )

        if import_line == -1:
            # There's no existing import, so, let's see if we have a *** Settings *** section.
            # If we don't we have to create the whole settings, otherwise, we'll add the statement
            # as the first thing in the existing *** Settings *** section.
            if completion_context.type == CompletionType.shell:
                import_line = 0
                prefix = "*** Settings ***\n"
            elif self.import_location_info.setting_section_node_info is None:
                import_line = 0
                prefix = "*** Settings ***\n"
            else:
                import_line = (self.import_location_info.
                               setting_section_node_info.node.end_lineno - 1)

        text = keyword_name

        if keyword_name in self.imported_keyword_name_to_keyword:
            check = lib_import or resource_path
            if check:
                basename = os.path.basename(check)
                if basename.endswith((".txt", ".py", ".robot", ".resource")):
                    basename = os.path.splitext(basename)[0]
                text = f"{basename}.{keyword_name}"

        text_edit = TextEdit(
            Range(
                start=Position(selection.line, token.col_offset + col_delta),
                end=Position(selection.line, token.end_col_offset),
            ),
            text,
        )

        additional_text_edits: List[TextEdit] = []

        if lib_import is not None:
            additional_text_edits.append(
                TextEdit(
                    Range(start=Position(import_line, 0),
                          end=Position(import_line, 0)),
                    f"{prefix}Library    {lib_import}\n",
                ))
        elif resource_path is not None:
            additional_text_edits.append(
                TextEdit(
                    Range(start=Position(import_line, 0),
                          end=Position(import_line, 0)),
                    f"{prefix}Resource    {resource_path}\n",
                ))

        # text_edit = None
        self.completion_items.append(
            CompletionItem(
                label,
                kind=CompletionItemKind.Reference,
                text_edit=text_edit,
                insertText=text_edit.newText,
                documentation="",
                insertTextFormat=InsertTextFormat.Snippet,
                documentationFormat=MarkupKind.PlainText,
                additionalTextEdits=additional_text_edits,
                data=data,
            ).to_dict())
예제 #16
0
def _create_range(d, offset1, offset2):
    from robocorp_ls_core.lsp import Range

    return Range(d.offset_to_line_col(offset1), d.offset_to_line_col(offset2))
예제 #17
0
def complete(completion_context):
    """
    :param CompletionContext completion_context:
    """
    import itertools
    from robocorp_ls_core.lsp import (
        TextEdit,
        Range,
        Position,
        CompletionItem,
        CompletionItemKind,
    )

    section_name = completion_context.get_current_section_name()
    if section_name:
        from robotframework_ls.impl.string_matcher import RobotStringMatcher

        section = completion_context.get_section(section_name)
        if section is not None:
            selection = completion_context.sel  #: :type selection: DocumentSelection
            line_to_col = selection.line_to_column
            if line_to_col.endswith("  "):
                return []
            replace_to_col = selection.col
            if section.names_in_brackets:
                for i, c in enumerate(line_to_col):
                    if c.isspace():
                        continue
                    elif c == "[":
                        line_to_col = line_to_col[i + 1:]
                        replace_from_col = i
                        break
                    else:
                        return []
                else:
                    return []

                matcher = RobotStringMatcher(line_to_col)

            else:
                # i.e.: Needs to be the first char
                matcher = RobotStringMatcher(line_to_col)
                replace_from_col = 0

            ret = []
            for word in sorted(itertools.chain(section.names,
                                               section.aliases)):
                if matcher.accepts(word):
                    if section.names_in_brackets:
                        label = "[%s]" % (word, )
                        line = selection.current_line
                        replacement = "[%s]" % (word, )
                        if line[selection.col:].startswith("]"):
                            replace_to_col += 1

                    else:
                        label = word
                        replacement = word

                    text_edit = TextEdit(
                        Range(
                            start=Position(selection.line, replace_from_col),
                            end=Position(selection.line, replace_to_col),
                        ),
                        replacement,
                    )
                    # text_edit = None
                    ret.append(
                        CompletionItem(label,
                                       kind=CompletionItemKind.Keyword,
                                       text_edit=text_edit).to_dict())

            return ret

    return []
예제 #18
0
def test_document_line_edit():
    doc = Document("file:///uri", u"itshelloworld")
    change = TextDocumentContentChangeEvent(
        Range(Position(0, 3), Position(0, 8)), 0, u"goodbye")
    doc.apply_change(change)
    assert doc.source == u"itsgoodbyeworld"