def _validate(ls: LanguageServer, uri: str): # Jedi script = get_script(ls, uri) result = [ types.Diagnostic(types.Range( types.Position(x.line - 1, x.column), types.Position(x.until_line - 1, x.until_column)), 'Invalid syntax', types.DiagnosticSeverity.Error, source='jedi') for x in script.get_syntax_errors() ] if result: ls.publish_diagnostics(uri, result) return # pyflakes pyflakes_check(script._code, script.path, PyflakesReporter(result, script, config['pyflakes_errors'])) # pycodestyle codestyleopts = get_pycodestyle_options(ls, uri) CodestyleChecker(script.path, script._code.splitlines(True), codestyleopts, CodestyleReport(codestyleopts, result)).check_all() if config['mypy_enabled']: try: _mypy_check(ls, uri, script, result) except Exception as e: ls.show_message(f'mypy check error: {e}', types.MessageType.Warning) ls.publish_diagnostics(uri, result)
def _get_document_symbols( code_lines: List[str], names: List[Name], current: Optional[Name] = None) -> List[types.DocumentSymbol]: # Looks like names are sorted by order of appearance, so # children are after their parents result = [] while names: if current and names[0].parent() != current: break name = names.pop(0) if name.type == 'param': continue children = _get_document_symbols(code_lines, names, name) line = name.line - 1 r = types.Range(types.Position(line, name.column), types.Position(line, len(code_lines[line]) - 1)) result.append( types.DocumentSymbol(name.name, _DOCUMENT_SYMBOL_KINDS.get( name.type, types.SymbolKind.Null), r, r, children=children or None)) return result
def _get_locations(defs: List[Name]) -> List[types.Location]: return [ types.Location( from_fs_path(d.module_path), types.Range(types.Position(d.line - 1, d.column), types.Position(d.line - 1, d.column + len(d.name)))) for d in defs if d.module_path ]
def syntaxError(self, _filename, msg, lineno, offset, _text): line = lineno - 1 col = offset or 0 self.result.append( types.Diagnostic(types.Range( types.Position(line, col), types.Position(line, len(self._get_codeline(line)) - col)), msg, types.DiagnosticSeverity.Error, source='pyflakes'))
def error(self, line_number, offset, text, check): code = text[:4] if self._ignore_code(code) or code in self.expected: return line = line_number - 1 self.result.append( types.Diagnostic( types.Range( types.Position(line, offset), types.Position(line, len(self.lines[line].rstrip('\n\r')))), text, types.DiagnosticSeverity.Warning, code, 'pycodestyle'))
def flake(self, message): line = message.lineno - 1 if message.__class__.__name__ in self.errors: severity = types.DiagnosticSeverity.Error else: severity = types.DiagnosticSeverity.Warning self.result.append( types.Diagnostic(types.Range( types.Position(line, message.col), types.Position(line, len(self._get_codeline(line)))), message.message % message.message_args, severity, source='pyflakes'))
def test_completion(): uri = 'file://test_completion.py' content = ''' def foo(a, *, b, c=None): pass foo''' doc = Document(uri, content) server.workspace.get_document = Mock(return_value=doc) aserver.completionFunction = aserver._completions_snippets completion = aserver.completions( server, types.CompletionParams( types.TextDocumentIdentifier(uri), types.Position(4, 3), types.CompletionContext(types.CompletionTriggerKind.Invoked))) assert len(completion.items) == 2 item = completion.items[0] assert item.insertText is None assert item.label == 'foo' assert item.sortText == 'aafoo' assert item.insertTextFormat is None item = completion.items[1] assert item.label == 'foo(a, b)' assert item.insertTextFormat == types.InsertTextFormat.Snippet assert item.insertText == 'foo(${1:a}, b=${2:b})$0'
def completions(ls: LanguageServer, params: types.CompletionParams): script = get_script(ls, params.textDocument.uri) completions = script.complete(params.position.line + 1, params.position.character) code_line = script._code_lines[params.position.line] word_match = RE_WORD.match(code_line[params.position.character:]) if word_match: word_rest = word_match.end() else: word_rest = 0 r = types.Range( types.Position(params.position.line, params.position.character), types.Position(params.position.line, params.position.character + word_rest)) return types.CompletionList(False, list(completionFunction(completions, r)))
def _get_text_edits(changes: ChangedFile) -> List[types.TextEdit]: result = [] old_lines = split_lines(changes._module_node.get_code(), keepends=True) new_lines = split_lines(changes.get_new_code(), keepends=True) line_number = 0 start = None replace_lines = False lines: List[str] = [] def _append(): if replace_lines: end = types.Position(line_number) else: end = start result.append(types.TextEdit(types.Range(start, end), ''.join(lines))) for line in differ.compare(old_lines, new_lines): kind = line[0] if kind == '?': continue if kind == '-': if not start: start = types.Position(line_number) replace_lines = True line_number += 1 continue if kind == '+': if not start: start = types.Position(line_number) lines.append(line[2:]) continue if start: _append() start = None replace_lines = False lines = [] line_number += 1 if start: _append() return result
def _symbols(): for name in names: if name.type == 'param': continue parent = name.parent() parent_name = parent and parent.full_name if parent_name: module_name = name.module_name if parent_name == module_name: parent_name = None elif parent_name.startswith(f'{module_name}.'): parent_name = parent_name[len(module_name) + 1:] yield types.SymbolInformation( name.name, _DOCUMENT_SYMBOL_KINDS.get(name.type, types.SymbolKind.Null), types.Location( uri, types.Range( types.Position(name.line - 1, name.column), types.Position(name.line - 1, len(code_lines[name.line - 1]) - 1))), parent_name)
def _mypy_check(ls: LanguageServer, uri: str, script: Script, result: List[types.Diagnostic]): from mypy import api assert jediEnvironment is not None version_info = jediEnvironment.version_info filename = to_fs_path(uri) lines = api.run([ '--python-executable', jediEnvironment.executable, '--python-version', f'{version_info.major}.{version_info.minor}', '--config-file', get_mypy_config(ls, uri), '--hide-error-context', '--show-column-numbers', '--show-error-codes', '--no-pretty', '--show-absolute-path', '--no-error-summary', filename ]) if lines[1]: ls.show_message(lines[1], types.MessageType.Error) return for line in lines[0].split('\n'): parts = line.split(':', 4) if len(parts) < 5: continue fn, row, column, err_type, message = parts if fn != filename: continue row = int(row) - 1 column = int(column) - 1 if err_type.strip() == 'note': severity = types.DiagnosticSeverity.Hint else: severity = types.DiagnosticSeverity.Warning result.append( types.Diagnostic(types.Range( types.Position(row, column), types.Position(row, len(script._code_lines[row]))), message.strip(), severity, source='mypy')) return result
def test_hover(): uri = 'file://test_hover.py' content = ''' def foo(a, *, b, c=None): """docstring""" pass foo''' doc = Document(uri, content) server.workspace.get_document = Mock(return_value=doc) h = aserver.hover( server, types.TextDocumentPositionParams(doc, types.Position(5, 0))) assert h is not None assert isinstance(h.contents, types.MarkupContent) assert h.contents.kind == types.MarkupKind.PlainText assert h.contents.value == 'foo(a, *, b, c=None)\n\ndocstring'
def _append(): if replace_lines: end = types.Position(line_number) else: end = start result.append(types.TextEdit(types.Range(start, end), ''.join(lines)))
def unexpectedError(self, _filename, msg): self.result.append( types.Diagnostic(types.Range(types.Position(), types.Position()), msg, types.DiagnosticSeverity.Error, source='pyflakes'))