@@ -38,85 +38,70 @@ def pylsp_format_range(document, range, options=None): # pylint: disable=redefi
38
38
return _format (document , lines = lines , options = options )
39
39
40
40
41
- def _format (document , lines = None , options = None ):
42
- source = document .source
43
- # Yapf doesn't work with CRLF/CR line endings, so we replace them by '\n'
44
- # and restore them below when adding new lines
45
- eol_chars = get_eol_chars (source )
46
- if eol_chars in ['\r ' , '\r \n ' ]:
47
- source = source .replace (eol_chars , '\n ' )
48
-
41
+ def get_style_config (document_path , options = None ):
49
42
# Get the default styles as a string
50
43
# for a preset configuration, i.e. "pep8"
51
44
style_config = file_resources .GetDefaultStyleForDir (
52
- os .path .dirname (document . path )
45
+ os .path .dirname (document_path )
53
46
)
54
- if options is not None :
55
- # We have options passed from LSP format request
56
- # let's pass them to the formatter.
57
- # First we want to get a dictionary of the preset style
58
- # to pass instead of a string so that we can modify it
59
- style_config = style .CreateStyleFromConfig (style_config )
47
+ if options is None :
48
+ return style_config
60
49
61
- use_tabs = style_config ['USE_TABS' ]
62
- indent_width = style_config ['INDENT_WIDTH' ]
50
+ # We have options passed from LSP format request
51
+ # let's pass them to the formatter.
52
+ # First we want to get a dictionary of the preset style
53
+ # to pass instead of a string so that we can modify it
54
+ style_config = style .CreateStyleFromConfig (style_config )
63
55
64
- if options . get ( 'tabSize' ) is not None :
65
- indent_width = max ( int ( options . get ( 'tabSize' )), 1 )
56
+ use_tabs = style_config [ 'USE_TABS' ]
57
+ indent_width = style_config [ 'INDENT_WIDTH' ]
66
58
67
- if options .get ('insertSpaces' ) is not None :
68
- # TODO is it guaranteed to be a boolean, or can it be a string?
69
- use_tabs = not options .get ('insertSpaces' )
59
+ if options .get ('tabSize' ) is not None :
60
+ indent_width = max (int (options .get ('tabSize' )), 1 )
70
61
71
- if use_tabs :
72
- # Indent width doesn't make sense when using tabs
73
- # the specifications state: "Size of a tab in spaces"
74
- indent_width = 1
62
+ if options .get ('insertSpaces' ) is not None :
63
+ # TODO is it guaranteed to be a boolean, or can it be a string?
64
+ use_tabs = not options .get ('insertSpaces' )
75
65
76
- style_config ['USE_TABS' ] = use_tabs
77
- style_config ['INDENT_WIDTH' ] = indent_width
78
- style_config ['CONTINUATION_INDENT_WIDTH' ] = indent_width
66
+ if use_tabs :
67
+ # Indent width doesn't make sense when using tabs
68
+ # the specifications state: "Size of a tab in spaces"
69
+ indent_width = 1
79
70
80
- for style_option , value in options .items ():
81
- # Apply arbitrary options passed as formatter options
82
- if style_option not in style_config :
83
- # ignore if it's not a known yapf config
84
- continue
71
+ style_config ['USE_TABS' ] = use_tabs
72
+ style_config ['INDENT_WIDTH' ] = indent_width
73
+ style_config ['CONTINUATION_INDENT_WIDTH' ] = indent_width
85
74
86
- style_config [style_option ] = value
75
+ for style_option , value in options .items ():
76
+ # Apply arbitrary options passed as formatter options
77
+ if style_option not in style_config :
78
+ # ignore if it's not a known yapf config
79
+ continue
87
80
88
- diff_txt , changed = FormatCode (
89
- source ,
90
- lines = lines ,
91
- filename = document .filename ,
92
- print_diff = True ,
93
- style_config = style_config
94
- )
81
+ style_config [style_option ] = value
95
82
96
- if not changed :
97
- return []
83
+ return style_config
98
84
99
- patch_generator = whatthepatch .parse_patch (diff_txt )
100
- diff = next (patch_generator )
101
- patch_generator .close ()
102
85
86
+ def diff_to_text_edits (diff , eol_chars ):
103
87
# To keep things simple our text edits will be line based.
104
88
# We will also return the edits uncompacted, meaning a
105
89
# line replacement will come in as a line remove followed
106
90
# by a line add instead of a line replace.
107
- textEdits = []
91
+ text_edits = []
108
92
# keep track of line number since additions
109
93
# don't include the line number it's being added
110
94
# to in diffs. lsp is 0-indexed so we'll start with -1
111
95
prev_line_no = - 1
96
+
112
97
for change in diff .changes :
113
98
if change .old and change .new :
114
99
# old and new are the same line, no change
115
100
# diffs are 1-indexed
116
101
prev_line_no = change .old - 1
117
102
elif change .new :
118
103
# addition
119
- textEdits .append ({
104
+ text_edits .append ({
120
105
'range' : {
121
106
'start' : {
122
107
'line' : prev_line_no + 1 ,
@@ -132,7 +117,7 @@ def _format(document, lines=None, options=None):
132
117
elif change .old :
133
118
# remove
134
119
lsp_line_no = change .old - 1
135
- textEdits .append ({
120
+ text_edits .append ({
136
121
'range' : {
137
122
'start' : {
138
123
'line' : lsp_line_no ,
@@ -151,23 +136,64 @@ def _format(document, lines=None, options=None):
151
136
})
152
137
prev_line_no = lsp_line_no
153
138
139
+ return text_edits
140
+
141
+
142
+ def ensure_eof_new_line (document , eol_chars , text_edits ):
154
143
# diffs don't include EOF newline https://github.com/google/yapf/issues/1008
155
144
# we'll add it ourselves if our document doesn't already have it and the diff
156
145
# does not change the last line.
157
- if not source .endswith (eol_chars ) and diff .changes \
158
- and diff .changes [- 1 ].old and diff .changes [- 1 ].new :
159
- textEdits .append ({
160
- 'range' : {
161
- 'start' : {
162
- 'line' : prev_line_no ,
163
- 'character' : 0
164
- },
165
- 'end' : {
166
- 'line' : prev_line_no + 1 ,
167
- 'character' : 0
168
- }
146
+ if document .source .endswith (eol_chars ):
147
+ return
148
+
149
+ lines = document .lines
150
+ last_line_number = len (lines ) - 1
151
+
152
+ if text_edits and text_edits [- 1 ]['range' ]['start' ]['line' ] >= last_line_number :
153
+ return
154
+
155
+ text_edits .append ({
156
+ 'range' : {
157
+ 'start' : {
158
+ 'line' : last_line_number ,
159
+ 'character' : 0
169
160
},
170
- 'newText' : diff .changes [- 1 ].line + eol_chars
171
- })
161
+ 'end' : {
162
+ 'line' : last_line_number + 1 ,
163
+ 'character' : 0
164
+ }
165
+ },
166
+ 'newText' : lines [- 1 ] + eol_chars
167
+ })
168
+
169
+
170
+ def _format (document , lines = None , options = None ):
171
+ source = document .source
172
+ # Yapf doesn't work with CRLF/CR line endings, so we replace them by '\n'
173
+ # and restore them below when adding new lines
174
+ eol_chars = get_eol_chars (source )
175
+ if eol_chars in ['\r ' , '\r \n ' ]:
176
+ source = source .replace (eol_chars , '\n ' )
177
+
178
+ style_config = get_style_config (document_path = document .path , options = options )
179
+
180
+ diff_txt , changed = FormatCode (
181
+ source ,
182
+ lines = lines ,
183
+ filename = document .filename ,
184
+ print_diff = True ,
185
+ style_config = style_config
186
+ )
187
+
188
+ if not changed :
189
+ return []
190
+
191
+ patch_generator = whatthepatch .parse_patch (diff_txt )
192
+ diff = next (patch_generator )
193
+ patch_generator .close ()
194
+
195
+ text_edits = diff_to_text_edits (diff = diff , eol_chars = eol_chars )
196
+
197
+ ensure_eof_new_line (document = document , eol_chars = eol_chars , text_edits = text_edits )
172
198
173
- return textEdits
199
+ return text_edits
0 commit comments