77from yapf .yapflib import file_resources
88from yapf .yapflib .yapf_api import FormatCode
99
10+ import whatthepatch
11+
1012from pylsp import hookimpl
1113from pylsp ._utils import get_eol_chars
1214
@@ -39,17 +41,16 @@ def pylsp_format_range(document, range): # pylint: disable=redefined-builtin
3941def _format (document , lines = None ):
4042 # Yapf doesn't work with CR line endings, so we replace them by '\n'
4143 # and restore them below.
42- replace_cr = False
4344 source = document .source
4445 eol_chars = get_eol_chars (source )
4546 if eol_chars == '\r ' :
46- replace_cr = True
4747 source = source .replace ('\r ' , '\n ' )
4848
49- new_source , changed = FormatCode (
49+ diff_txt , changed = FormatCode (
5050 source ,
5151 lines = lines ,
5252 filename = document .filename ,
53+ print_diff = True ,
5354 style_config = file_resources .GetDefaultStyleForDir (
5455 os .path .dirname (document .path )
5556 )
@@ -58,16 +59,57 @@ def _format(document, lines=None):
5859 if not changed :
5960 return []
6061
61- if replace_cr :
62- new_source = new_source .replace ('\n ' , '\r ' )
63-
64- # I'm too lazy at the moment to parse diffs into TextEdit items
65- # So let's just return the entire file...
66- return [{
67- 'range' : {
68- 'start' : {'line' : 0 , 'character' : 0 },
69- # End char 0 of the line after our document
70- 'end' : {'line' : len (document .lines ), 'character' : 0 }
71- },
72- 'newText' : new_source
73- }]
62+ patch_generator = whatthepatch .parse_patch (diff_txt )
63+ diff = next (patch_generator )
64+ patch_generator .close ()
65+
66+ # To keep things simple our text edits will be line based
67+ # and uncompacted
68+ textEdits = []
69+ # keep track of line number since additions
70+ # don't include the line number it's being added
71+ # to in diffs. lsp is 0-indexed so we'll start with -1
72+ prev_line_no = - 1
73+ for change in diff .changes :
74+ if change .old and change .new :
75+ # no change
76+ # diffs are 1-indexed
77+ prev_line_no = change .old - 1
78+ elif change .new :
79+ # addition
80+ textEdits .append ({
81+ 'range' : {
82+ 'start' : {
83+ 'line' : prev_line_no + 1 ,
84+ 'character' : 0
85+ },
86+ 'end' : {
87+ 'line' : prev_line_no + 1 ,
88+ 'character' : 0
89+ }
90+ },
91+ 'newText' : change .line + eol_chars
92+ })
93+ elif change .old :
94+ # remove
95+ lsp_line_no = change .old - 1
96+ textEdits .append ({
97+ 'range' : {
98+ 'start' : {
99+ 'line' : lsp_line_no ,
100+ 'character' : 0
101+ },
102+ 'end' : {
103+ # From LSP spec:
104+ # If you want to specify a range that contains a line
105+ # including the line ending character(s) then use an
106+ # end position denoting the start of the next line.
107+ 'line' : lsp_line_no + 1 ,
108+ 'character' : 0
109+ }
110+ },
111+ 'newText' : ''
112+ })
113+ prev_line_no = lsp_line_no
114+
115+ return textEdits
0 commit comments