@@ -83,6 +83,122 @@ function M._calculate_lines(suggestion)
83
83
}
84
84
end
85
85
86
+ --- @private
87
+ --- @class TextDeletion
88
+ --- @field range lsp.Range
89
+
90
+ --- @private
91
+ --- @class InlineInsertion
92
+ --- @field text string
93
+ --- @field line integer
94
+ --- @field character integer
95
+
96
+ --- @private
97
+ --- @class TextInsertion
98
+ --- @field text string
99
+ --- @field line integer insert lines at this line
100
+
101
+ --- @private
102
+ --- @class InlineEditPreview
103
+ --- @field deletions ? TextDeletion[]
104
+ --- @field inline_insertion ? InlineInsertion
105
+ --- @field lines_insertion ? TextInsertion
106
+
107
+ --- @param bufnr integer
108
+ --- @param edit lsp.TextEdit
109
+ --- @return InlineEditPreview
110
+ function M .preview_inline_edit (bufnr , edit )
111
+ local text = edit .newText
112
+ local range = edit .range
113
+ local start_line = range .start .line
114
+ local start_char = range .start .character
115
+ local end_line = range [" end" ].line
116
+ local end_char = range [" end" ].character
117
+
118
+ -- Split text by newline. Use plain=true to handle trailing newline correctly.
119
+ local new_lines = vim .split (text , " \n " , { plain = true })
120
+ local num_new_lines = # new_lines
121
+
122
+ local old_lines = vim .api .nvim_buf_get_lines (bufnr , start_line , end_line + 1 , false )
123
+ local num_old_lines = # old_lines
124
+
125
+ local is_same_line = start_line == end_line
126
+ local is_deletion = text == " "
127
+ local is_insertion = is_same_line and start_char == end_char
128
+
129
+ if is_deletion and is_insertion then
130
+ -- no-op
131
+ return {}
132
+ end
133
+
134
+ if is_same_line and is_deletion then
135
+ -- inline deletion
136
+ return {
137
+ deletions = {
138
+ {
139
+ range = edit .range ,
140
+ },
141
+ },
142
+ }
143
+ end
144
+
145
+ if is_insertion and num_new_lines == 1 and text ~= " " then
146
+ -- inline insertion
147
+ return {
148
+ inline_insertion = {
149
+ text = text ,
150
+ line = start_line ,
151
+ character = start_char ,
152
+ },
153
+ }
154
+ end
155
+
156
+ if is_insertion and num_new_lines > 1 then
157
+ if start_char == # old_lines [1 ] and new_lines [1 ] == " " then
158
+ -- insert lines after the start line
159
+ return {
160
+ line_insertion = {
161
+ text = table.concat (vim .list_slice (new_lines , 2 ), " \n " ),
162
+ line = start_line ,
163
+ },
164
+ }
165
+ end
166
+
167
+ if end_char == 0 and new_lines [num_new_lines ] == " " then
168
+ -- insert lines before the end line
169
+ return {
170
+ lines_insertion = {
171
+ text = table.concat (vim .list_slice (new_lines , 1 , num_new_lines - 1 ), " \n " ),
172
+ line = start_line ,
173
+ },
174
+ }
175
+ end
176
+ end
177
+
178
+ -- insert lines in the middle
179
+ local prefix = old_lines [1 ]:sub (1 , start_char )
180
+ local suffix = old_lines [num_old_lines ]:sub (end_char + 1 )
181
+ local new_lines_extend = vim .deepcopy (new_lines )
182
+ new_lines_extend [1 ] = prefix .. new_lines_extend [1 ]
183
+ new_lines_extend [num_new_lines ] = new_lines_extend [num_new_lines ] .. suffix
184
+ local insertion = table.concat (new_lines_extend , " \n " )
185
+
186
+ return {
187
+ deletions = {
188
+ {
189
+ range = {
190
+ start = { line = start_line , character = 0 },
191
+ [" end" ] = { line = end_line , character = # old_lines [num_old_lines ] },
192
+ },
193
+ },
194
+ },
195
+ lines_insertion = {
196
+ text = insertion ,
197
+ line = end_line ,
198
+ },
199
+ }
200
+ end
201
+
86
202
--- @private
87
203
--- @param edits copilotlsp.InlineEdit[]
88
204
--- @param ns_id integer
@@ -103,11 +219,11 @@ function M._display_next_suggestion(edits, ns_id)
103
219
local lines = M ._calculate_lines (suggestion )
104
220
105
221
local line_replacement = false
222
+ -- check if the edit is a inline insert or delete but not a whole line replacement
106
223
if lines .same_line then
107
224
local row = suggestion .range .start .line
108
225
local start_col = suggestion .range .start .character
109
226
local end_col = suggestion .range [" end" ].character
110
-
111
227
local line_text = vim .api .nvim_buf_get_lines (bufnr , row , row + 1 , false )[1 ]
112
228
if start_col == 0 and end_col == # line_text then
113
229
line_replacement = true
0 commit comments