Semantic Diff

#9116 Keep line breaks inside literals when formatting

1 commit

85f31fbb15ef96bd168d6e99055ad4808810d6e0..pr-9116

9de0dae95 · cknitt + Claude · Oct 28, 2026, 15:42 UTC

Write the formatter's own line breaks with the file's newline

Why

Since #9042, formatting converted the whole source to LF and the output back to CRLF, string literals included, so bsc -format changed the program when a string held a raw line break of the other kind. Each conversion also dropped only one CR before an LF, so a comment with \r\r\n changed on every run (#9100).

The source is now parsed as is, and the printer writes the line breaks it emits with the newline of the source (CRLF when the first line break is CRLF), while literals keep their bytes. bsc -format, res_parser -print res and the editor's format command do the same. In the examples below, \r and \n stand for CR and LF, the heading holds the input, and each version is what bsc -format prints for it.

modifiedFormat let x = 1\r\nlet s = "a\nb"\r\n

text
Before
After
let x = 1\r\nlet s = "a\r\nb"\r\nlet x = 1\r\nlet s = "a\nb"\r\n

modifiedFormat let x = 1\nlet s = "a\r\nb"\n

text
Before
After
let x = 1\nlet s = "a\nb"\nlet x = 1\nlet s = "a\r\nb"\n

modifiedFormat let x = 1\n/* a\r\r\nb */\n

text
Before first run, then second run
After first and second run
let x = 1\n/* a\r\n b */\n let x = 1\n/* a\n b */\nlet x = 1\n/* a\n b */\n

Review

  • Why does the comment lose its CRs? The printer reindents a multi-line /* … */ comment and writes that comment's line breaks itself, as it already did for the lines after the first.