Пример #1
0
    def test_code_action_return_list(self):
        response = self.client.lsp.send_request(
            CODE_ACTION,
            CodeActionParams(
                text_document=TextDocumentIdentifier(uri='file://return.list'),
                range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=1, character=1),
                ),
                context=CodeActionContext(
                    diagnostics=[
                        Diagnostic(
                            range=Range(
                                start=Position(line=0, character=0),
                                end=Position(line=1, character=1),
                            ),
                            message='diagnostic'
                        )
                    ],
                    only=[CodeActionKind.Refactor]
                )
            )
        ).result(timeout=CALL_TIMEOUT)

        assert response[0]['title'] == 'action1'
        assert response[1]['title'] == 'action2'
        assert response[1]['kind'] == CodeActionKind.Refactor
        assert response[2]['title'] == 'cmd1'
        assert response[2]['command'] == 'cmd1'
        assert response[2]['arguments'] == [1, 'two']
Пример #2
0
    def test_code_action_return_none(self):
        response = self.client.lsp.send_request(
            CODE_ACTION,
            CodeActionParams(
                text_document=TextDocumentIdentifier(uri='file://return.none'),
                range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=1, character=1),
                ),
                context=CodeActionContext(
                    diagnostics=[
                        Diagnostic(
                            range=Range(
                                start=Position(line=0, character=0),
                                end=Position(line=1, character=1),
                            ),
                            message='diagnostic',
                        )
                    ],
                    only=[CodeActionKind.Refactor],
                )
            )
        ).result(timeout=CALL_TIMEOUT)

        assert response is None
Пример #3
0
        def f(
            params: DeclarationParams
        ) -> Optional[Union[Location, List[Location], List[LocationLink]]]:
            location = Location(
                uri='uri',
                range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=1, character=1),
                ),
            )

            location_link = LocationLink(
                target_uri='uri',
                target_range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=1, character=1),
                ),
                target_selection_range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=2, character=2),
                ),
                origin_selection_range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=3, character=3),
                ),
            )

            return {    # type: ignore
                'file://return.location': location,
                'file://return.location_list': [location],
                'file://return.location_link_list': [location_link],
            }.get(params.text_document.uri, None)
Пример #4
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), sync_kind=TextDocumentSyncKind.INCREMENTAL)
    change = TextDocumentContentChangeEvent(
        range=Range(start=Position(line=1, character=4), end=Position(line=2, character=11)),
        range_length=0,
        text=u'print a, b')
    doc.apply_change(change)

    assert doc.lines == [
        "def hello(a, b):\n",
        "    print a, b\n"
    ]

    doc = Document('file:///uri', u''.join(old), sync_kind=TextDocumentSyncKind.INCREMENTAL)
    change = TextDocumentContentChangeEvent(
        range=Range(start=Position(line=1, character=4), end=Position(line=2, character=11)),
        text=u'print a, b')
    doc.apply_change(change)

    assert doc.lines == [
        "def hello(a, b):\n",
        "    print a, b\n"
    ]
Пример #5
0
def test_range_to_utf16():
    assert range_to_utf16(
        ['x="😋"'], Range(start=Position(line=0, character=3), end=Position(line=0, character=4))
    ) == Range(start=Position(line=0, character=3), end=Position(line=0, character=5))

    range = Range(start=Position(line=0, character=3), end=Position(line=0, character=4))
    range_to_utf16(['x="😋"'], range)
    assert range == Range(start=Position(line=0, character=3), end=Position(line=0, character=4))
Пример #6
0
def _validate(ls, params: Union[DidChangeTextDocumentParams,
                                DidCloseTextDocumentParams,
                                DidOpenTextDocumentParams]):
    ls.show_message_log("Validating CP2K input...")

    diagnostics = []

    text_doc = ls.workspace.get_document(params.text_document.uri)
    parser = CP2KInputParser()

    with open(text_doc.path, "r") as fhandle:
        try:
            parser.parse(fhandle)
        except (TokenizerError, ParserError) as exc:
            ctx = exc.args[1]
            line = ctx.line.rstrip()

            msg = f"Syntax error: {exc.args[0]} ({exc.__cause__})"

            linenr = ctx.linenr - 1
            colnr = ctx.colnr

            if colnr is not None:
                count = 0  # number of underline chars after (positiv) or before (negative) the marker if ref_colnr given
                nchars = colnr  # relevant line length

                if ctx.ref_colnr is not None:
                    count = ctx.ref_colnr - ctx.colnr
                    nchars = min(ctx.ref_colnr,
                                 ctx.colnr)  # correct if ref comes before

                if ctx.colnrs:
                    # shift by the number of left-stripped ws
                    # ctx.colnrs contains the left shift for each possibly continued line
                    nchars += ctx.colnrs[
                        0]  # assume no line-continuation for now

                # at least do one context
                count = max(1, count)

                erange = Range(start=Position(line=linenr,
                                              character=colnr + 1 - count),
                               end=Position(line=linenr, character=colnr + 1))

            else:
                erange = Range(start=Position(line=linenr, character=1),
                               end=Position(line=linenr, character=len(line)))

            diagnostics += [
                Diagnostic(range=erange, message=msg, source=type(ls).__name__)
            ]

    ls.publish_diagnostics(text_doc.uri, diagnostics)
Пример #7
0
 def f(params: PrepareRenameParams) -> Optional[Union[Range, PrepareRename]]:
     return {    # type: ignore
         'file://return.range': Range(
             start=Position(line=0, character=0),
             end=Position(line=1, character=1),
         ),
         'file://return.prepare_rename': PrepareRename(
             range=Range(
                 start=Position(line=0, character=0),
                 end=Position(line=1, character=1),
             ),
             placeholder='placeholder',
         ),
     }.get(params.text_document.uri, None)
Пример #8
0
        def f(
            params: DocumentSymbolParams
        ) -> Union[List[SymbolInformation], List[DocumentSymbol]]:
            symbol_info = SymbolInformation(
                name='symbol',
                kind=SymbolKind.Namespace,
                location=Location(
                    uri='uri',
                    range=Range(
                        start=Position(line=0, character=0),
                        end=Position(line=1, character=1),
                    ),
                ),
                container_name='container',
                deprecated=False,
            )

            document_symbol_inner = DocumentSymbol(
                name='inner_symbol',
                kind=SymbolKind.Number,
                range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=1, character=1),
                ),
                selection_range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=1, character=1),
                ),
            )

            document_symbol = DocumentSymbol(
                name='symbol',
                kind=SymbolKind.Object,
                range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=10, character=10),
                ),
                selection_range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=10, character=10),
                ),
                detail='detail',
                children=[document_symbol_inner],
                deprecated=True,
            )

            return {    # type: ignore
                'file://return.symbol_information_list': [symbol_info],
                'file://return.document_symbol_list': [document_symbol],
            }.get(params.text_document.uri, None)
Пример #9
0
def exception_to_diagnostic(exc: BaseException):
    """Convert an exception into a diagnostic we can send to the client."""

    # Config errors sometimes wrap the true cause of the problem
    if isinstance(exc, ConfigError) and exc.__cause__ is not None:
        exc = exc.__cause__

    if isinstance(exc, SyntaxError):
        path = pathlib.Path(exc.filename or "")
        line = (exc.lineno or 1) - 1
    else:
        tb = exc.__traceback__
        frame = traceback.extract_tb(tb)[-1]
        path = pathlib.Path(frame.filename)
        line = (frame.lineno or 1) - 1

    message = type(exc).__name__ if exc.args.count == 0 else exc.args[0]

    diagnostic = Diagnostic(
        range=Range(
            start=Position(line=line, character=0),
            end=Position(line=line + 1, character=0),
        ),
        message=message,
        severity=DiagnosticSeverity.Error,
    )

    return Uri.from_fs_path(str(path)), diagnostic
Пример #10
0
        def f(params: HoverParams) -> Optional[Hover]:
            range = Range(
                start=Position(line=0, character=0),
                end=Position(line=1, character=1),
            )

            return {
                'file://return.marked_string':
                Hover(
                    range=range,
                    contents=MarkedString(
                        language='language',
                        value='value',
                    ),
                ),
                'file://return.marked_string_list':
                Hover(
                    range=range,
                    contents=[
                        MarkedString(
                            language='language',
                            value='value',
                        ), 'str type'
                    ],
                ),
                'file://return.markup_content':
                Hover(
                    range=range,
                    contents=MarkupContent(kind=MarkupKind.Markdown,
                                           value='value'),
                ),
            }.get(params.text_document.uri, None)
Пример #11
0
    def _find_snippet_insert_position(self) -> Union[Position, Range]:
        """Returns the position inside the document where new test cases
        can be inserted.

        If the <tests> section does not exists in the file, the best aproximate
        position where the tests should be inserted is returned (acording to the IUC
        best practices tag order).

        Returns:
            Position: The position where the test cases can be inserted in the document.
        """
        tool = self.tool_document
        section = tool.find_element(TESTS)
        if section:
            content_range = tool.get_content_range(section)
            if content_range:
                return content_range.end
            else:  # is self closed <tests/>
                start = tool.get_position_before(section)
                end = tool.get_position_after(section)
                return Range(start=start, end=end)
        else:
            section = tool.find_element(OUTPUTS)
            if section:
                return tool.get_position_after(section)
            section = tool.find_element(INPUTS)
            if section:
                return tool.get_position_after(section)
            section = tool.find_element(TOOL)
            if section:
                content_range = tool.get_content_range(section)
                if content_range:
                    return content_range.end
            return Position(line=0, character=0)
    def _build_diagnostics(
            self,
            error_log: etree._ListErrorLog,
            xml_tree: Optional[etree._ElementTree] = None) -> List[Diagnostic]:
        """Gets a list of diagnostics from the XSD validation error log.

        Args:
            error_log (etree._ListErrorLog): The error log generated after XSD schema validation.
            xml_tree (Optional[etree.ElementTree], optional): The element tree associated with
            the error log. Defaults to None.

        Raises:
            ExpandMacrosFoundException: This is raised when a macro ``expand`` element is found in the error log.
            The ``expand`` element is not part of the XSD so, when this exception is raised, we know that
            the document must expand the macros before validation.

        Returns:
            List[Diagnostic]: The list of resulting diagnostic items found in the error log.
        """
        diagnostics = []
        for error in error_log.filter_from_errors():
            if "expand" in error.message:
                raise ExpandMacrosFoundException(xml_tree)

            result = Diagnostic(
                range=Range(
                    start=Position(line=error.line - 1,
                                   character=error.column),
                    end=Position(line=error.line - 1, character=error.column),
                ),
                message=error.message,
                source=self.server_name,
            )
            diagnostics.append(result)
        return diagnostics
Пример #13
0
async def lsp_completion(
    ls: LanguageServer,
    params: CompletionParams,
) -> Optional[List[CompletionItem]]:
    await asyncio.sleep(DEBOUNCE_DELAY)
    items: List[CompletionItem] = []

    ast = await buildout.parse(ls, params.text_document.uri, True)
    for line in ast.lines:
        pos = params.position
        (var_name, var_type, value) = line
        ci = CompletionItem(label=var_name,
                            text_edit=TextEdit(
                                range=Range(
                                    start=Position(line=pos.line,
                                                   character=pos.character),
                                    end=Position(line=pos.line,
                                                 character=pos.character +
                                                 len(var_name))),
                                new_text=var_name,
                            ),
                            kind=CompletionItemKind.Variable,
                            documentation=MarkupContent(
                                kind=MarkupKind.Markdown,
                                value=f"{var_name} : {var_type} = {value}",
                            ))
        items.append(ci)
    return items
 def _build_diagnostics_for_expanded_macros(
         self, tool: GalaxyToolXmlDocument,
         invalid_document_error) -> List[Diagnostic]:
     virtual_uri = tool.xml_document.document.uri.replace(
         "file", "gls-expand")
     diagnostics = [
         Diagnostic(
             range=tool.get_macros_range(),
             message=error.message,
             source=self.server_name,
             code=DiagnosticCodes.INVALID_EXPANDED_TOOL,
             related_information=[
                 DiagnosticRelatedInformation(
                     message=
                     ("The validation error ocurred on the expanded version of "
                      "the document, i.e. after replacing macros. "
                      "Click here to preview the expanded document."),
                     location=Location(
                         uri=f"{virtual_uri}{EXPAND_DOCUMENT_URI_SUFFIX}",
                         range=Range(
                             start=Position(line=error.line - 1,
                                            character=error.column),
                             end=Position(line=error.line - 1,
                                          character=error.column),
                         ),
                     ),
                 )
             ],
         )
         for error in invalid_document_error.error_log.filter_from_errors()
     ]
     return diagnostics
Пример #15
0
    def test_range_formatting_return_list(self):
        response = self.client.lsp.send_request(
            RANGE_FORMATTING,
            DocumentRangeFormattingParams(
                text_document=TextDocumentIdentifier(uri='file://return.list'),
                range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=1, character=1),
                ),
                options=FormattingOptions(
                    tab_size=2,
                    insert_spaces=True,
                    trim_trailing_whitespace=True,
                    insert_final_newline=True,
                    trim_final_newlines=True,
                ),
            ),
        ).result(timeout=CALL_TIMEOUT)

        assert response

        assert response[0]['newText'] == 'text'
        assert response[0]['range']['start']['line'] == 0
        assert response[0]['range']['start']['character'] == 0
        assert response[0]['range']['end']['line'] == 1
        assert response[0]['range']['end']['character'] == 1
Пример #16
0
    def _calculate_external_changes_for_macro(
        self,
        tool: GalaxyToolXmlDocument,
        macro_file_definition: ImportedMacrosFile,
        macro: MacroData,
        params: CodeActionParams,
    ) -> Dict[str, List[TextEdit]]:
        """Returns a dictionary with the document uri and the collection of TextEdit operations for that particular document.

        The edits will add the macro definition to the given imported macros file and replace the refactored macro with the
        corresponding <expand> element in the tool wrapper."""
        macros_xml_doc = macro_file_definition.document
        if macro_file_definition.file_uri is None or macros_xml_doc is None or macros_xml_doc.root is None:
            return {}
        macros_root = macros_xml_doc.root
        insert_position = macros_xml_doc.get_position_after_last_child(
            macros_root)
        insert_range = Range(start=insert_position, end=insert_position)
        macro_xml = f'<xml name="{macro.name}">\n{macro.content}\n</xml>'
        final_macro_xml = self._adapt_format(macros_xml_doc, insert_range,
                                             macro_xml)
        external_edit = TextEdit(
            range=insert_range,
            new_text=final_macro_xml,
        )
        changes = {
            params.text_document.uri: [
                self._edit_replace_range_with_macro_expand(
                    tool, macro, params.range)
            ],
            macro_file_definition.file_uri: [external_edit],
        }
        return changes
Пример #17
0
def lsp_text_edits(
    document: Document, changed_file: ChangedFile
) -> List[TextEdit]:
    """Take a jedi `ChangedFile` and convert to list of text edits.

    Handles inserts, replaces, and deletions within a text file.

    Additionally, makes sure returned code is syntactically valid Python.
    """
    new_code = changed_file.get_new_code()
    if not is_valid_python(new_code):
        return []

    old_code = document.source
    position_lookup = PositionLookup(old_code)
    text_edits = []
    for opcode in get_opcodes(old_code, new_code):
        if opcode.op in _OPCODES_CHANGE:
            start = position_lookup.get(opcode.old_start)
            end = position_lookup.get(opcode.old_end)
            new_text = new_code[opcode.new_start : opcode.new_end]
            text_edits.append(
                TextEdit(
                    range=Range(start=start, end=end),
                    new_text=new_text,
                )
            )
    return text_edits
Пример #18
0
 def on_error(e: UnexpectedToken):
     diagnostics.append(Diagnostic(
         range=Range(
             start=Position(line=e.line - 1, character=e.column - 1),
             end=Position(line=e.line - 1, character=e.column)
         ), message=user_repr(e)))
     return True
 def get_range_for_context(self, xml_document: XmlDocument,
                           context: XmlContext) -> Range:
     if context.node is None:
         return Range()
     start_offset, end_offset = context.node.get_offsets(context.offset)
     return convert_document_offsets_to_range(xml_document.document,
                                              start_offset, end_offset)
Пример #20
0
def test_document_empty_edit():
    doc = Document('file:///uri', u'')
    change = TextDocumentContentChangeEvent(
        range=Range(start=Position(line=0, character=0), end=Position(line=0, character=0)),
        range_length=0,
        text=u'f')
    doc.apply_change(change)
    assert doc.source == u'f'
Пример #21
0
def test_document_line_edit():
    doc = Document('file:///uri', u'itshelloworld')
    change = TextDocumentContentChangeEvent(
        range=Range(start=Position(line=0, character=3), end=Position(line=0, character=8)),
        range_length=0,
        text=u'goodbye')
    doc.apply_change(change)
    assert doc.source == u'itsgoodbyeworld'
Пример #22
0
    def emit(self, record: logging.LogRecord) -> None:

        conditions = [
            "sphinx" not in record.name,
            record.levelno not in {logging.WARNING, logging.ERROR},
            not self.translator,
        ]

        if any(conditions):
            # Log the record as normal
            super().emit(record)
            return

        # Only process errors/warnings once.
        if not self.only_once.filter(record):
            return

        # Let sphinx do what it does to warning/error messages
        self.translator.filter(record)

        loc = record.location if isinstance(record, SphinxLogRecord) else ""
        doc, lineno = self.get_location(loc)
        line = lineno or 1
        logger.debug("Reporting diagnostic at %s:%s", doc, line)

        try:
            # Not every message contains a string...
            if not isinstance(record.msg, str):
                message = str(record.msg)
            else:
                message = record.msg

            # Only attempt to format args if there are args to format
            if record.args is not None and len(record.args) > 0:
                message = message % record.args

        except Exception:
            message = str(record.msg)
            logger.error("Unable to format diagnostic message: %s",
                         traceback.format_exc())

        diagnostic = Diagnostic(
            range=Range(
                start=Position(line=line - 1, character=0),
                end=Position(line=line, character=0),
            ),
            message=message,
            severity=DIAGNOSTIC_SEVERITY.get(record.levelno,
                                             DiagnosticSeverity.Warning),
        )

        if doc not in self.diagnostics:
            self.diagnostics[doc] = [diagnostic]
        else:
            self.diagnostics[doc].append(diagnostic)

        super().emit(record)
Пример #23
0
        def f(params: SelectionRangeParams) -> Optional[List[SelectionRange]]:
            if params.text_document.uri == 'file://return.list':
                root = SelectionRange(range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=10, character=10),
                ), )

                inner_range = SelectionRange(
                    range=Range(
                        start=Position(line=0, character=0),
                        end=Position(line=1, character=1),
                    ),
                    parent=root,
                )

                return [root, inner_range]
            else:
                return None
Пример #24
0
def declaration(ls: DiplomatLanguageServer,
                params: DeclarationParams) -> Location:
    if not ls.indexed:
        reindex_all(ls)
    uri_source = unquote(params.text_document.uri)
    ref_range = Range(start=params.position, end=params.position)
    ret = ls.svindexer.get_definition_from_location(
        Location(uri=uri_source, range=ref_range))
    return ret
 def f(params: LinkedEditingRangeParams
       ) -> Optional[LinkedEditingRanges]:
     if params.text_document.uri == 'file://return.ranges':
         return LinkedEditingRanges(
             ranges=[
                 Range(
                     start=Position(line=0, character=0),
                     end=Position(line=1, character=1),
                 ),
                 Range(
                     start=Position(line=1, character=1),
                     end=Position(line=2, character=2),
                 ),
             ],
             word_pattern='pattern',
         )
     else:
         return None
Пример #26
0
 def f(params: DocumentColorParams) -> List[ColorInformation]:
     return [
         ColorInformation(
             range=Range(
                 start=Position(line=0, character=0),
                 end=Position(line=1, character=1),
             ),
             color=Color(red=0.5, green=0.5, blue=0.5, alpha=0.5),
         )
     ]
Пример #27
0
def from_str(spec: str):
    """Create a range from the given string a:b-x:y"""
    start, end = spec.split("-")
    sl, sc = start.split(":")
    el, ec = end.split(":")

    return Range(
        start=Position(line=int(sl), character=int(sc)),
        end=Position(line=int(el), character=int(ec)),
    )
Пример #28
0
 def f(
     params: DocumentHighlightParams
 ) -> Optional[List[DocumentHighlight]]:
     if params.text_document.uri == 'file://return.list':
         return [
             DocumentHighlight(range=Range(
                 start=Position(line=0, character=0),
                 end=Position(line=1, character=1),
             ), ),
             DocumentHighlight(
                 range=Range(
                     start=Position(line=1, character=1),
                     end=Position(line=2, character=2),
                 ),
                 kind=DocumentHighlightKind.Write,
             ),
         ]
     else:
         return None
Пример #29
0
def references(ls: DiplomatLanguageServer,
               params: ReferenceParams) -> T.List[Location]:
    """Returns completion items."""
    if not ls.indexed:
        reindex_all(ls)
    uri_source = unquote(params.text_document.uri)
    ref_range = Range(start=params.position, end=params.position)
    ret = ls.svindexer.get_refs_from_location(
        Location(uri=uri_source, range=ref_range))
    return ret
Пример #30
0
    def test_semantic_tokens_range_return_none(self):
        response = self.client.lsp.send_request(
            TEXT_DOCUMENT_SEMANTIC_TOKENS_RANGE,
            SemanticTokensRangeParams(
                text_document=TextDocumentIdentifier(uri='file://return.none'),
                range=Range(
                    start=Position(line=0, character=0),
                    end=Position(line=10,
                                 character=80)))).result(timeout=CALL_TIMEOUT)

        assert response is None