Esempio n. 1
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
Esempio n. 2
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
Esempio n. 3
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)
Esempio n. 4
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)
Esempio n. 5
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
Esempio n. 6
0
def test_position():
    assert Position(1, 2) == Position(1, 2)
    assert Position(1, 2) != Position(2, 2)
    assert Position(1, 2) <= Position(2, 2)
    assert Position(2, 2) >= Position(2, 0)
    assert Position(1, 2) != 'something else'
    assert "1:2" == repr(Position(1, 2))
    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
Esempio n. 8
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 = {}
Esempio n. 9
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)
Esempio n. 10
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))))
Esempio n. 12
0
def test_word_at_position(doc):
    """
    Return the position under the cursor (or last in line if past the end)
    """
    assert doc.word_at_position(Position(0, 8)) == 'document'
    assert doc.word_at_position(Position(0, 1000)) == 'document'
    assert doc.word_at_position(Position(1, 5)) == 'for'
    assert doc.word_at_position(Position(2, 0)) == 'testing'
    assert doc.word_at_position(Position(4, 0)) == ''
Esempio n. 13
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)
Esempio n. 14
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"]
Esempio n. 15
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)]
Esempio n. 16
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",
    )
Esempio n. 17
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),
        )
Esempio n. 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,
    )
        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)]
Esempio n. 20
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
    ]
Esempio n. 21
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",
    ]
Esempio n. 22
0
def test_offset_at_position(doc):
    assert doc.offset_at_position(Position(0, 8)) == 8
    assert doc.offset_at_position(Position(1, 5)) == 14
    assert doc.offset_at_position(Position(2, 0)) == 13
    assert doc.offset_at_position(Position(2, 4)) == 17
    assert doc.offset_at_position(Position(3, 6)) == 27
    assert doc.offset_at_position(Position(3, 7)) == 27
    assert doc.offset_at_position(Position(3, 8)) == 28
    assert doc.offset_at_position(Position(4, 0)) == 39
    assert doc.offset_at_position(Position(5, 0)) == 39
Esempio n. 23
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
Esempio n. 24
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),
        ),
    )
Esempio n. 25
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))
Esempio n. 26
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
Esempio n. 27
0
    def role_to_completion_item(
        self, name: str, role, match: "re.Match", position: Position
    ) -> CompletionItem:
        """Convert an rst role to its CompletionItem representation.

        With domain support it's necessary to compute the CompletionItem representation
        specifically for each completion site. See
        :meth:`~esbonio.lsp.directives.Directives.directive_to_completion_item` for
        more historical information.

        For some reason, even though these completion items are constructed in the same
        manner as the ones for directives using them in VSCode does not feel as nice....

        Parameters
        ----------
        name:
           The name of the role as a user would type into an reStructuredText document.
        role:
           The implementation of the role.
        match:
           The regular expression match object that represents the line we are providing
           the autocomplete suggestions for.
        position:
           The position in the source code where the autocompletion request was sent
           from.
        """

        groups = match.groupdict()

        line = position.line
        start = position.character - len(groups["role"])
        end = position.character

        insert_text = f":{name}:"

        item = CompletionItem(
            name,
            kind=CompletionItemKind.Function,
            filter_text=insert_text,
            detail="role",
            text_edit=TextEdit(
                range=Range(Position(line, start), Position(line, end)),
                new_text=insert_text,
            ),
        )

        self.logger.debug("Item %s", dump(item))
        return item
def char_pos_to_position(buf, position):
    seekpos = 0
    position = position - 1
    for lineno, line in enumerate(buf.split('\n')):
        if seekpos + (len(line) + 1) > position:
            return Position(lineno, position - seekpos)
        seekpos += len(line) + 1
Esempio n. 29
0
def test_completions():
    """An example test which does very little"""
    completion_list = server.completions(
        fake_server,
        CompletionParams(TextDocumentIdentifier('file://fake_doc.txt'), Position(0, 2), None))
    # test the list is empty for now
    assert completion_list.items == []
    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()