@@ -252,22 +252,34 @@ export class GhostStreamingParser {
252252 return null
253253 }
254254
255+ // Trim trailing whitespace from search for better matching
256+ const searchTrimmed = searchWithoutMarker . trimEnd ( )
257+
255258 // Extract the new content
256259 let newContent = replaceWithoutMarker
257- if ( replaceWithoutMarker . startsWith ( searchWithoutMarker ) ) {
260+ if ( replaceWithoutMarker . startsWith ( searchTrimmed ) ) {
258261 // LLM preserved the search context - remove it
259- newContent = replaceWithoutMarker . substring ( searchWithoutMarker . length )
262+ newContent = replaceWithoutMarker . substring ( searchTrimmed . length )
260263 }
261264
265+ // Trim trailing newlines from the content (LLM often adds extras)
266+ newContent = newContent . trimEnd ( )
267+
262268 // Check if current line (where cursor is) has content
263- // Extract the last line before cursor marker in the original search
264269 const lines = prefix . split ( "\n" )
265270 const currentLine = lines [ lines . length - 1 ]
266271 const currentLineHasContent = currentLine . trim ( ) . length > 0
267272
268- // Only add newline if current line has content
269- if ( currentLineHasContent && ! newContent . startsWith ( "\n" ) ) {
270- newContent = "\n" + newContent
273+ if ( currentLineHasContent ) {
274+ // Current line has content - add newline if not present
275+ if ( ! newContent . startsWith ( "\n" ) ) {
276+ newContent = "\n" + newContent
277+ }
278+ } else {
279+ // Current line is empty - remove any leading newline LLM might have added
280+ if ( newContent . startsWith ( "\n" ) ) {
281+ newContent = newContent . substring ( 1 )
282+ }
271283 }
272284
273285 return { text : newContent , prefix, suffix }
0 commit comments