diff --git a/src/renderer/src/components/editor/monaco-content-sync.test.ts b/src/renderer/src/components/editor/monaco-content-sync.test.ts index 30f833d379c..96996207963 100644 --- a/src/renderer/src/components/editor/monaco-content-sync.test.ts +++ b/src/renderer/src/components/editor/monaco-content-sync.test.ts @@ -102,6 +102,27 @@ describe('monaco content sync', () => { }) it.each([ + [ + 'CRLF file content into a CRLF model', + 'first\r\nsecond\r\nlast', + '\r\n', + 'first\r\nsecond\r\nlast\r\nnext', + '\r\nnext' + ], + [ + 'mixed file content into a CRLF model', + 'first\r\nsecond\r\nlast', + '\r\n', + 'first\r\nsecond\rlast\nnext', + '\r\nnext' + ], + [ + 'adjacent bare and paired CRs into a CRLF model', + 'first\r\nsecond\r\nlast', + '\r\n', + 'first\r\nsecond\r\nlast\r\r\n\nnext\r', + '\r\n\r\n\r\nnext\r\n' + ], [ 'CRLF file content into an LF model', 'first\nsecond\nlast', diff --git a/src/renderer/src/components/editor/monaco-content-sync.ts b/src/renderer/src/components/editor/monaco-content-sync.ts index fa19928b89d..60bf36107b4 100644 --- a/src/renderer/src/components/editor/monaco-content-sync.ts +++ b/src/renderer/src/components/editor/monaco-content-sync.ts @@ -2,14 +2,19 @@ import type { editor } from 'monaco-editor' export type MonacoContentSyncMode = 'undoable' | 'read-only-live-tail' -function normalizeToModelEol(content: string, model: editor.ITextModel): string { +function normalizeToModelEol( + content: string, + model: editor.ITextModel, + currentContent: string +): string { const eol = model.getEOL() // Why: Monaco normalizes model line endings, while filesystem content keeps // its raw EOLs. Compare the representation Monaco can actually retain. - if (eol === '\n' && !content.includes('\r')) { + if ((eol === '\n' && !content.includes('\r')) || content === currentContent) { return content } - return content.replace(/\r\n|\r|\n/g, eol) + const separators = eol === '\r\n' ? /\r(?!\n)|(?