def visit_symbol(self, ctx: antlr4.ParserRuleContext, kind:int=SymbolKind.Variable, visit_children:bool=True):
        id_ctx = ctx.getChild(0, Parser.IdentifierContext)

        symbol = DocumentSymbol(
            name=id_ctx.start.text,
            kind=kind,
            range=Range(
                start=Position(ctx.start.line-1, ctx.start.column),
                end=Position(ctx.stop.line-1, ctx.stop.column)
            ),
            selection_range=Range(
                start=Position(id_ctx.start.line-1, id_ctx.start.column),
                end=Position(id_ctx.stop.line-1, id_ctx.stop.column)
            ),
            detail="",
            children=[],
            deprecated=False
        )

        logging.debug(f"found symbol: {symbol.name}")
        self.scope.append(symbol)

        if visit_children:
            logging.debug(f"Visiting children of symbol: {symbol.name}")
            prev_scope = self.scope
            self.scope = symbol.children
            res = self.visitChildren(ctx)
            self.scope = prev_scope
        return res
Пример #2
0
def test_range_from_utf16():
    assert range_from_utf16(['x="😋"'], Range(Position(0, 3),
                                                Position(0, 5))) == Range(
                                                    Position(0, 3),
                                                    Position(0, 4))

    range = Range(Position(0, 3), Position(0, 5))
    range_from_utf16(['x="😋"'], range)
    assert range == Range(Position(0, 3), Position(0, 5))
Пример #3
0
def _validate(ls, params):
    ls.show_message_log("Validating CP2K input...")

    diagnostics = []

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

    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]}"

            if exc.__cause__:
                msg += f"({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"] is not None:
                    # 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(Position(linenr, colnr + 1 - count),
                               Position(linenr, colnr + 1))

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

            diagnostics += [
                Diagnostic(erange,
                           msg,
                           source=type(cp2k_inp_server).__name__,
                           related_information=[])
            ]

    ls.publish_diagnostics(text_doc.uri, diagnostics)
Пример #4
0
def _get_range(p: SourcePosition = None):
    if p is None:
        return Range(
            Position(),
            Position(0, sys.maxsize),
        )
    else:
        return Range(
            Position(p.line - 1, p.column - 1),
            Position(p.end_line - 1, p.end_column - 1),
        )
Пример #5
0
    def _get_macros_range(self, document: Document,
                          xml_tree: etree.ElementTree) -> Optional[Range]:
        """Given a XML document and its corresponding ElementTree, finds
        the first macro import element and returns its Range position
        inside the document.

        Args:
            document (Document): The XML tool document.
            xml_tree (etree.ElementTree): The corresponding ElementTree of the document.

        Returns:
            Optional[Range]: The Range position of the import file if it exists.
        """
        try:
            import_element = xml_tree.find("macros//import")
            line_number = import_element.sourceline - 1
            filename = import_element.text
            start = document.lines[line_number].find(filename)
            end = start + len(filename)
            return Range(
                Position(line_number, start),
                Position(line_number, end),
            )
        except BaseException:
            return None
Пример #6
0
def lsp_text_edits(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
    """
    old_code = (
        changed_file._module_node.get_code()  # pylint: disable=protected-access
    )
    new_code = changed_file.get_new_code()
    opcode_position_lookup_old = get_opcode_position_lookup(old_code)
    text_edits = []
    for opcode in get_opcodes(old_code, new_code):
        if opcode.op in _OPCODES_CHANGE:
            start = opcode_position_lookup_old[opcode.old_start]
            end = opcode_position_lookup_old[opcode.old_end]
            start_char = opcode.old_start - start.range_start
            end_char = opcode.old_end - end.range_start
            new_text = new_code[opcode.new_start:opcode.new_end]
            text_edits.append(
                TextEdit(
                    range=Range(
                        start=Position(line=start.line, character=start_char),
                        end=Position(line=end.line, character=end_char),
                    ),
                    new_text=new_text,
                ))
    return text_edits
Пример #7
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(
                    Position(error.line - 1, error.column),
                    Position(error.line - 1, error.column),
                ),
                error.message,
                source=self.server_name,
            )
            diagnostics.append(result)
        return diagnostics
    def _find_snippet_insert_position(self) -> Union[Position, Range]:
        """Returns the position inside the document where command section
        can be inserted.

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

        Returns:
            Position: The position where the command section can be inserted in the document.
        """
        tool = self.tool_document
        section = tool.find_element(COMMAND)
        if section:
            content_range = tool.get_element_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, end)
        else:
            section = tool.find_element(ENV_VARIABLES)
            if section:
                return tool.get_position_before(section)
            section = tool.find_element(CONFIGFILES)
            if section:
                return tool.get_position_before(section)
            section = tool.find_element(INPUTS)
            if section:
                return tool.get_position_before(section)
            section = tool.find_element(TOOL)
            if section:
                return tool.get_element_content_range(section).end
            return Position()
Пример #9
0
def test_invalid_textxfile_diagnostics_on_doc_change(client_server):
    client, server = client_server

    doc = doc_from_path(TEXTXFILE_WITH_ERROR_PATH, 'textxfile')
    content = doc.text
    doc.text = ''
    # Add doc to server's workspace directly
    server.workspace.put_document(doc)

    versioned_doc = VersionedTextDocumentIdentifier(doc.uri, doc.version + 1)
    content_change = TextDocumentContentChangeEvent(
        Range(Position(0, 0), Position(0, 0)), 0, content
    )
    send_text_doc_did_change_request(client, versioned_doc, [content_change])

    params = builtin_notifications.get(timeout=CALL_TIMEOUT)

    assert params.uri == doc.uri

    d = params.diagnostics[0]
    r = d.range
    assert d.message == "Expected ',' or ']'"
    assert r.start.line == 0
    assert r.start.character == 0
    assert r.end.line == 0
    assert r.end.character == 500

    # Remove all docs from the workspace
    server.workspace._docs = {}
Пример #10
0
def _make_diagnostic(linter, node, message):
    start_pos = Position(node.parse_tree.loc)
    end_pos = Position(node.parse_tree.loc + 1)
    return Diagnostic(Range(start_pos, end_pos),
                      message=message,
                      code=linter.code,
                      severity=linter.severity)
Пример #11
0
def _validate(ls, params):
    """
    Validate a document and publish diagnostics
    """
    text_doc = ls.workspace.get_document(params.textDocument.uri)
    source = text_doc.source
    diagnostics = []
    line_index = -1
    # test comment
    for line in source.splitlines():
        logging.debug("*** %s", line)
        line_index += 1
        col_index = -1
        while True:
            if col_index == -1:
                col_index = str.find(line, "e")
            else:
                col_index = str.find(line, "e", col_index + 1)
            if col_index == -1:
                logging.debug("The remainder of line %s is efree", line_index)
                break
            msg = "Character e at column {}".format(col_index)
            d = Diagnostic(Range(Position(line_index, col_index),
                                 Position(line_index, col_index + 1)),
                           msg,
                           source=type(server).__name__)
            diagnostics.append(d)
            logging.debug("e at line %s, col %s", line_index, col_index)
    ls.publish_diagnostics(text_doc.uri, diagnostics)
Пример #12
0
    def write(self, line):
        """This method lets us catch output from Sphinx."""

        match = PROBLEM_PATTERN.match(line)
        if match:
            filepath = match.group("file")
            severity = PROBLEM_SEVERITY.get(match.group("type"),
                                            PROBLEM_SEVERITY["ERROR"])
            diagnostics = self.diagnostics.get(filepath, None)

            if diagnostics is None:
                diagnostics = DiagnosticList()

            try:
                line_number = int(match.group("line"))
            except (TypeError, ValueError) as exc:
                self.logger.debug("Unable to parse line number: '%s'",
                                  match.group("line"))
                self.logger.debug(exc)

                line_number = 1

            range_ = Range(Position(line_number - 1, 0),
                           Position(line_number, 0))
            diagnostics.append(
                Diagnostic(range_,
                           match.group("message"),
                           severity=severity,
                           source="sphinx"))

            self.diagnostics[filepath] = diagnostics

        self.sphinx_log.info(line)
Пример #13
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.lines == ["def hello(a, b):\n", "    print a, b\n"]
 def __init__(self, filename, ctx, kind=None):
     super().__init__(
         name=ctx.getChild(0, Parser.IdentifierContext).start.text,
         kind=kind,
         location=Location(
             filename,
             Range(start=Position(ctx.start.line, ctx.start.column),
                   end=Position(ctx.stop.line, ctx.stop.column))))
class TestXmlUtils:
    @pytest.mark.parametrize(
        "source, offset, expected_position",
        [
            ("<tool></tool>", 0, Position(0, 0)),
            ("<tool></tool>", 13, Position(0, 13)),
            ("<tool></tool>\n", 14, Position(1, 0)),
            ("<tool>\n<description/>\n<inputs>\n</tool>", 6, Position(0, 6)),
            ("<tool>\n<description/>\n<inputs>\n</tool>", 7, Position(1, 0)),
            ("<tool>\n<description/>\n<inputs>\n</tool>", 21, Position(1, 14)),
            ("<tool>\n<description/>\n<inputs>\n</tool>", 22, Position(2, 0)),
            ("<tool>\n<description/>\n<inputs>\n</tool>", 30, Position(2, 8)),
            ("<tool>\n<description/>\n<inputs>\n</tool>", 38, Position(3, 7)),
        ],
    )
    def test_convert_document_offset_to_position_returns_expected_result(
            self, source: str, offset: int,
            expected_position: Position) -> None:
        document = TestUtils.to_document(source)

        actual_position = convert_document_offset_to_position(document, offset)

        assert actual_position == expected_position

    @pytest.mark.parametrize(
        "source, start_offset, end_offset, expected_range",
        [
            ("<tool></tool>", 0, 6, Range(Position(0, 0), Position(0, 6))),
            ("<tool>\n</tool>", 0, 14, Range(Position(0, 0), Position(1, 7))),
            ("<tool>\n<description/>\n</tool>", 7, 21,
             Range(Position(1, 0), Position(1, 14))),
            ("<tool>\n<description/>\n</tool>\n", 0, 30,
             Range(Position(0, 0), Position(3, 0))),
        ],
    )
    def test_convert_document_offsets_to_range_returns_expected_result(
            self, source: str, start_offset: int, end_offset: int,
            expected_range: Range) -> None:
        document = TestUtils.to_document(source)

        actual_range = convert_document_offsets_to_range(
            document, start_offset, end_offset)

        assert actual_range == expected_range
Пример #16
0
def test_document_full_edit():
    old = ["def hello(a, b):\n", "    print a\n", "    print b\n"]
    doc = Document('file:///uri',
                   u''.join(old),
                   sync_kind=TextDocumentSyncKind.FULL)
    change = TextDocumentContentChangeEvent(
        Range(Position(1, 4), Position(2, 11)), 0, u'print a, b')
    doc.apply_change(change)

    assert doc.lines == ["print a, b"]
Пример #17
0
    def format(self, content: str, params: DocumentFormattingParams) -> List[TextEdit]:
        """Given the document contents returns the list of TextEdits
        needed to properly layout the document.
        """
        formatted_result = self._format_document(content, params.options.tabSize)

        lines = content.count("\n")
        start = Position(0, 0)
        end = Position(lines + 1, 0)
        return [TextEdit(Range(start, end), formatted_result)]
Пример #18
0
def _diagnostic(msg: str, line = 1, col = 1, end_line = None, end_col = sys.maxsize, severity = DiagnosticSeverity.Error):
    if end_line is None:
        end_line = line
    return Diagnostic(
        Range(
            Position(line - 1, col - 1),
            Position(end_line - 1, end_col - 1),
        ),
        msg,
        severity=severity,
    )
Пример #19
0
        def formatting(params: DocumentFormattingParams):
            doc = self.workspace.get_document(params.textDocument.uri)
            content = doc.source
            tokens, remain = self._parser.parse(content)
            if remain:
                self.show_message("CMake parser failed")
                return None

            formatted = Formatter().format(tokens)
            lines = content.count("\n")
            return [TextEdit(Range(Position(0, 0), Position(lines + 1, 0)), formatted)]
Пример #20
0
def lsp_diagnostic(error: jedi.api.errors.SyntaxError) -> Diagnostic:
    """Get LSP Diagnostic from Jedi SyntaxError"""
    return Diagnostic(
        range=Range(
            start=Position(line=error.line - 1, character=error.column),
            end=Position(line=error.line - 1, character=error.column),
        ),
        message=str(error).strip("<>"),
        severity=DiagnosticSeverity.Error,
        source="jedi",
    )
    def visitInstantiation(self, ctx:Parser.InstantiationContext):
        for child in ctx.getChildren(lambda x: isinstance(x, Parser.IdentifierContext)):
            symbol = DocumentSymbol(
                name=child.start.text,
                kind=SymbolKind.Variable,
                range=Range(
                    start=Position(ctx.start.line-1, ctx.start.column),
                    end=Position(ctx.stop.line-1, ctx.stop.column)
                ),
                selection_range=Range(
                    start=Position(child.start.line-1, child.start.column),
                    end=Position(child.stop.line-1, child.stop.column)
                ),
                detail="",
                children=[],
                deprecated=False
            )
            logging.debug(f"found symbol: {symbol.name}")
            self.scope.append(symbol)

        return None
Пример #22
0
def test_range():
    assert Range(Position(1, 2), Position(3, 4)) \
        == Range(Position(1, 2), Position(3, 4))
    assert Range(Position(0, 2), Position(3, 4)) \
        != Range(Position(1, 2), Position(3, 4))
    assert Range(Position(0, 2), Position(3, 4)) != 'something else'
    assert "1:2-3:4" == repr(Range(Position(1, 2), Position(3, 4)))
Пример #23
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.lines == [
        "print 'a'\n",
        "print 'b'\n",
        "o",
    ]
Пример #24
0
def jump_to_definition(ls, c: TextDocumentPositionParams) -> List[Location]:
    doc = ls.workspace.get_document(c.textDocument.uri)
    items = find_definition(doc.uri, doc.source, c.position.line + 1,
                            c.position.character)
    return [
        Location(
            path_to_uri(item.module_path),
            Range(
                Position(item.line - 1, item.column),
                Position(item.line - 1, item.column + len(item.name)),
            ),
        ) for item in items
    ]
Пример #25
0
    def get_range_for_context(self, document: Document,
                              context: XmlContext) -> Range:
        start_offset, end_offset = context.token.get_offsets(context.offset)
        start_line = max(document.source.count(NEW_LINE, 0, start_offset), 0)
        start_character = start_offset - document.source.rfind(
            NEW_LINE, 0, start_offset)
        end_line = max(document.source.count(NEW_LINE, 0, end_offset), 0)
        end_character = end_offset - document.source.rfind(
            NEW_LINE, 0, end_offset)

        return Range(
            Position(start_line, start_character),
            Position(end_line, end_character),
        )
Пример #26
0
 def _cursor_word(self,
                  uri: str,
                  position: Position,
                  include_all: bool = True) -> Optional[Tuple[str, Range]]:
     line = self._cursor_line(uri, position)
     cursor = position.character
     for m in re.finditer(r'\w+', line):
         end = m.end() if include_all else cursor
         if m.start() <= cursor <= m.end():
             word = (line[m.start():end],
                     Range(Position(position.line, m.start()),
                           Position(position.line, end)))
             return word
     return None
Пример #27
0
def _get_diagnostic_range(err: TextXError) -> Range:
    """Prettifies error message.

    Args:
        err: an instance of TextXError (syntax or semantic)
    Returns:
        A range which should be highlighted
    Raises:
        None

    """
    # Mark a whole line ( 500 for now, should be len(doc.lines[line]) )
    line = 0 if err.line - 1 < 0 else err.line - 1
    return Range(Position(line, 0), Position(line, 500))
Пример #28
0
def lsp_range(name: Name) -> Range:
    """Get LSP range from Jedi definition.

    - jedi is 1-indexed for lines and 0-indexed for columns
    - LSP is 0-indexed for lines and 0-indexed for columns
    - Therefore, subtract 1 from Jedi's definition line
    """
    return Range(
        start=Position(line=name.line - 1, character=name.column),
        end=Position(
            line=name.line - 1,
            character=name.column + len(name.name),
        ),
    )
Пример #29
0
 def validate(self, source):
     self.itpr = check(source)
     diagnostics = []
     logging.debug(f'itpr errors: {self.itpr.errors}')
     for item in self.itpr.errors:
         l1 = item['lineno'] - 1
         c1 = item['col_offset']
         l2 = item['end_lineno'] - 1
         c2 = item['end_col_offset']
         msg = item['error'].message
         diagnostics.append(
             Diagnostic(range=Range(Position(l1, c1), Position(l2, c2)),
                        message=msg,
                        source="PDChecker"))
     return diagnostics
Пример #30
0
def test_location():
    assert Location(uri="file:///document.txt", range=Range(Position(1, 2), Position(3, 4))) \
        == Location(uri="file:///document.txt", range=Range(Position(1, 2), Position(3, 4)))
    assert Location(uri="file:///document.txt", range=Range(Position(1, 2), Position(3, 4))) \
        != Location(uri="file:///another.txt", range=Range(Position(1, 2), Position(3, 4)))
    assert Location(uri="file:///document.txt", range=Range(Position(1, 2), Position(3, 4))) \
        != 'something else'
    assert "file:///document.txt:1:2-3:4" == repr(
        Location(uri="file:///document.txt",
                 range=Range(Position(1, 2), Position(3, 4))))