1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
# Copyright 2017-2020 Palantir Technologies, Inc.
# Copyright 2021- Python Language Server Contributors.
import logging
import pycodestyle
from autopep8 import continued_indentation as autopep8_c_i
from autopep8 import fix_code
from pylsp import hookimpl
from pylsp._utils import get_eol_chars
log = logging.getLogger(__name__)
@hookimpl(tryfirst=True) # Prefer autopep8 over YAPF
def pylsp_format_document(config, workspace, document, options):
with workspace.report_progress("format: autopep8"):
log.info("Formatting document %s with autopep8", document)
return _format(config, document)
@hookimpl(tryfirst=True) # Prefer autopep8 over YAPF
def pylsp_format_range(config, workspace, document, range, options):
log.info("Formatting document %s in range %s with autopep8", document, range)
# First we 'round' the range up/down to full lines only
range["start"]["character"] = 0
range["end"]["line"] += 1
range["end"]["character"] = 0
# Add 1 for 1-indexing vs LSP's 0-indexing
line_range = (range["start"]["line"] + 1, range["end"]["line"])
return _format(config, document, line_range=line_range)
def _format(config, document, line_range=None):
options = _autopep8_config(config, document)
if line_range:
options["line_range"] = list(line_range)
# Temporarily re-monkey-patch the continued_indentation checker - #771
del pycodestyle._checks["logical_line"][pycodestyle.continued_indentation]
pycodestyle.register_check(autopep8_c_i)
# Autopep8 doesn't work with CR line endings, so we replace them by '\n'
# and restore them below.
replace_cr = False
source = document.source
eol_chars = get_eol_chars(source)
if eol_chars == "\r":
replace_cr = True
source = source.replace("\r", "\n")
new_source = fix_code(source, options=options)
# Switch it back
del pycodestyle._checks["logical_line"][autopep8_c_i]
pycodestyle.register_check(pycodestyle.continued_indentation)
if new_source == source:
return []
if replace_cr:
new_source = new_source.replace("\n", "\r")
# I'm too lazy at the moment to parse diffs into TextEdit items
# So let's just return the entire file...
return [
{
"range": {
"start": {"line": 0, "character": 0},
# End char 0 of the line after our document
"end": {"line": len(document.lines), "character": 0},
},
"newText": new_source,
}
]
def _autopep8_config(config, document=None):
# We user pycodestyle settings to avoid redefining things
path = document.path if document is not None else None
settings = config.plugin_settings("pycodestyle", document_path=path)
options = {
"exclude": settings.get("exclude"),
"hang_closing": settings.get("hangClosing"),
"ignore": settings.get("ignore"),
"max_line_length": settings.get("maxLineLength"),
"select": settings.get("select"),
"aggressive": settings.get("aggressive"),
}
# Filter out null options
return {k: v for k, v in options.items() if v}
|