@@ -38,85 +38,70 @@ def pylsp_format_range(document, range, options=None): # pylint: disable=redefi
3838 return _format (document , lines = lines , options = options )
3939
4040
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 ):
4942 # Get the default styles as a string
5043 # for a preset configuration, i.e. "pep8"
5144 style_config = file_resources .GetDefaultStyleForDir (
52- os .path .dirname (document . path )
45+ os .path .dirname (document_path )
5346 )
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
6049
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 )
6355
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' ]
6658
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 )
7061
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' )
7565
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
7970
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
8574
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
8780
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
9582
96- if not changed :
97- return []
83+ return style_config
9884
99- patch_generator = whatthepatch .parse_patch (diff_txt )
100- diff = next (patch_generator )
101- patch_generator .close ()
10285
86+ def diff_to_text_edits (diff , eol_chars ):
10387 # To keep things simple our text edits will be line based.
10488 # We will also return the edits uncompacted, meaning a
10589 # line replacement will come in as a line remove followed
10690 # by a line add instead of a line replace.
107- textEdits = []
91+ text_edits = []
10892 # keep track of line number since additions
10993 # don't include the line number it's being added
11094 # to in diffs. lsp is 0-indexed so we'll start with -1
11195 prev_line_no = - 1
96+
11297 for change in diff .changes :
11398 if change .old and change .new :
11499 # old and new are the same line, no change
115100 # diffs are 1-indexed
116101 prev_line_no = change .old - 1
117102 elif change .new :
118103 # addition
119- textEdits .append ({
104+ text_edits .append ({
120105 'range' : {
121106 'start' : {
122107 'line' : prev_line_no + 1 ,
@@ -132,7 +117,7 @@ def _format(document, lines=None, options=None):
132117 elif change .old :
133118 # remove
134119 lsp_line_no = change .old - 1
135- textEdits .append ({
120+ text_edits .append ({
136121 'range' : {
137122 'start' : {
138123 'line' : lsp_line_no ,
@@ -151,23 +136,64 @@ def _format(document, lines=None, options=None):
151136 })
152137 prev_line_no = lsp_line_no
153138
139+ return text_edits
140+
141+
142+ def ensure_eof_new_line (document , eol_chars , text_edits ):
154143 # diffs don't include EOF newline https://github.com/google/yapf/issues/1008
155144 # we'll add it ourselves if our document doesn't already have it and the diff
156145 # 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
169160 },
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 )
172198
173- return textEdits
199+ return text_edits
0 commit comments