forked from python-lsp/python-lsp-server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathautopep8_format.py
94 lines (72 loc) · 3.14 KB
/
autopep8_format.py
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
# Copyright 2017-2020 Palantir Technologies, Inc.
# Copyright 2021- Python Language Server Contributors.
import logging
import pycodestyle
from autopep8 import fix_code, continued_indentation as autopep8_c_i
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): # pylint: disable=unused-argument
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
): # pylint: disable=redefined-builtin,unused-argument
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'] + 1)
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}