@@ -6,21 +6,7 @@ import { dictionary } from '@shared/constants/dictionary'
66import { create_safe_path , sanitize_file_name } from '@/utils/path-sanitizer'
77import { FileItem } from '../utils/clipboard-parser'
88import { OriginalFileState } from '../types/original-file-state'
9-
10- /*
11- * Matches lines like:
12- * // ...
13- * # ...
14- * <!-- ...
15- * ; ...
16- * " ...
17- * ' ...
18- * {/* ...
19- * /* ...
20- */
21- const TRUNCATION_REGEX = / ^ \s * ( \/ \/ | # | < ! - - | ; | " | ' | \{ \/ \* | \/ \* ) \s * \. { 3 , } .* \s * $ /
22-
23- export const is_truncation_line = ( line : string ) => TRUNCATION_REGEX . test ( line )
9+ import { process_truncated_content } from '../utils/edit-formats/truncations'
2410
2511export const handle_truncated_edit = async (
2612 files : FileItem [ ]
@@ -126,154 +112,3 @@ export const handle_truncated_edit = async (
126112
127113 return { success : true , original_states, failed_files }
128114}
129-
130- const process_truncated_content = (
131- new_text : string ,
132- original_text : string
133- ) : string => {
134- const new_lines = new_text . split ( / \r ? \n / )
135- const original_lines = original_text . split ( / \r ? \n / )
136-
137- const blocks : { type : 'code' | 'truncation' ; lines : string [ ] } [ ] = [ ]
138- let buffer : string [ ] = [ ]
139-
140- for ( const line of new_lines ) {
141- if ( is_truncation_line ( line ) ) {
142- if ( buffer . length > 0 ) {
143- blocks . push ( { type : 'code' , lines : buffer } )
144- buffer = [ ]
145- }
146- blocks . push ( { type : 'truncation' , lines : [ line ] } )
147- } else {
148- buffer . push ( line )
149- }
150- }
151- if ( buffer . length > 0 ) {
152- blocks . push ( { type : 'code' , lines : buffer } )
153- }
154-
155- const output_lines : string [ ] = [ ]
156- let current_original_idx = 0 // Line index in original
157-
158- for ( let i = 0 ; i < blocks . length ; i ++ ) {
159- const block = blocks [ i ]
160-
161- if ( block . type == 'code' ) {
162- output_lines . push ( ...block . lines )
163-
164- // Try to sync with original to handle replacements (context consumption)
165- // We look for a suffix of this block in the original file.
166- // If found, we advance current_original_idx to the end of that match.
167- // This allows the block to "consume" original code, avoiding duplication.
168-
169- const search_window_size = 10
170- const suffix_lines = block . lines . slice ( - search_window_size )
171-
172- // Heuristic: Find the first occurrence of this suffix in Original after current_original_idx
173- let found_match = false
174- let match_end_idx = - 1
175-
176- // Try finding the largest possible suffix that matches
177- for ( let len = suffix_lines . length ; len >= 1 ; len -- ) {
178- const sub_suffix = suffix_lines . slice ( suffix_lines . length - len )
179- // Find this sequence of lines in original_lines starting at current_original_idx
180- const idx = find_line_sequence (
181- original_lines ,
182- sub_suffix ,
183- current_original_idx
184- )
185- if ( idx !== - 1 ) {
186- found_match = true
187- match_end_idx = idx + len
188- break
189- }
190- }
191-
192- if ( found_match ) {
193- current_original_idx = match_end_idx
194- }
195- } else {
196- // Truncation block
197- // We need to fill from current_original_idx up to the start of the Next Block.
198-
199- let fill_end_idx = original_lines . length
200-
201- if ( i + 1 < blocks . length ) {
202- const next_block = blocks [ i + 1 ]
203- if ( next_block . type == 'code' ) {
204- // Find where the next block starts in original
205- const prefix_lines = next_block . lines . slice ( 0 , 10 )
206- let found_next = false
207-
208- for ( let len = prefix_lines . length ; len >= 1 ; len -- ) {
209- const sub_prefix = prefix_lines . slice ( 0 , len )
210- const idx = find_line_sequence (
211- original_lines ,
212- sub_prefix ,
213- current_original_idx
214- )
215- if ( idx !== - 1 ) {
216- fill_end_idx = idx
217- found_next = true
218- break
219- }
220- }
221-
222- if ( ! found_next ) {
223- fill_end_idx = original_lines . length
224- }
225- }
226- }
227-
228- // Append original content
229- if ( fill_end_idx > current_original_idx ) {
230- output_lines . push (
231- ...original_lines . slice ( current_original_idx , fill_end_idx )
232- )
233- }
234- current_original_idx = fill_end_idx
235- }
236- }
237-
238- const result = output_lines . join ( '\n' )
239-
240- if ( original_text . endsWith ( '\n' ) && ! result . endsWith ( '\n' ) ) {
241- return result + '\n'
242- }
243-
244- return result
245- }
246-
247- const find_line_sequence = (
248- lines : string [ ] ,
249- sequence : string [ ] ,
250- start_idx : number
251- ) : number => {
252- if ( sequence . length == 0 ) return - 1
253- if ( start_idx >= lines . length ) return - 1
254-
255- // First pass: exact match (checking for correct indentation)
256- for ( let i = start_idx ; i <= lines . length - sequence . length ; i ++ ) {
257- let match = true
258- for ( let j = 0 ; j < sequence . length ; j ++ ) {
259- if ( lines [ i + j ] != sequence [ j ] ) {
260- match = false
261- break
262- }
263- }
264- if ( match ) return i
265- }
266-
267- // Second pass: loose match (trim)
268- for ( let i = start_idx ; i <= lines . length - sequence . length ; i ++ ) {
269- let match = true
270- for ( let j = 0 ; j < sequence . length ; j ++ ) {
271- if ( lines [ i + j ] . trim ( ) != sequence [ j ] . trim ( ) ) {
272- match = false
273- break
274- }
275- }
276- if ( match ) return i
277- }
278- return - 1
279- }
0 commit comments