Skip to content

fix(config_edit): stop write-back from adding CRs to multi-line attributes - #22

Open
s31teg wants to merge 1 commit into
eisber:mainfrom
s31teg:fix/crlf-attr-newlines
Open

s31teg wants to merge 1 commit into
eisber:mainfrom
s31teg:fix/crlf-attr-newlines

Conversation

@s31teg

@s31teg s31teg commented Oct 6, 2026

Copy link
Copy Markdown

Problem

Every save through ConfigEditor::to_bytes() added one carriage return per line break inside attribute values, so multi-line attributes degraded a little more with each lox config edit.

Loxone writes CRLF line endings but keeps line breaks inside attribute values as they are: bare LF in note text (Text="…"), CRLF in AutoPilot rule JSON (APC="…"). The CRLF post-process replaced every \n in the output, including those inside attributes. On the next load xml-rs kept the \r and re-emitted it as 
, so:

  • note *****\nOLD ON TRIGGERS became *****




\r\nOLD ON TRIGGERS after five lox config layout calls
  • AutoPilot rule JSON accumulated \r characters the same way

Fix

  • Convert LF → CRLF only outside start tags (to_crlf_outside_attrs), skipping comments, CDATA and processing instructions, mirroring normalize_loxone_xml.
  • Restore 
 alongside 
 in normalize_start_tag, so attribute values round-trip exactly as read (bare LF stays LF, CRLF stays CRLF).

Testing

  • New regression test test_crlf_file_keeps_lf_in_attr_values_across_saves: a Loxone-style file (BOM, CRLF, LF in note text, CRLF in AutoPilot JSON) is byte-identical after one and two saves. It fails on main and passes with this change.
  • cargo fmt --check, cargo clippy -- -D warnings, cargo build --release and cargo test all pass.
  • Checked on a real 2.4 MB project: a no-op save is byte-identical to the input, and lox config layout --only-new now changes only block coordinates (previously it also rewrote 59 notes and 2 AutoPilot rules).

…butes

Loxone writes CRLF line endings but keeps line breaks inside attribute
values as-is: bare LF in note text, CRLF in AutoPilot rule JSON. The
CRLF post-process converted every LF, including those inside attributes,
and xml-rs re-emitted the CR it read back as `
`. Each save added one
more carriage return per line break, mangling notes and AutoPilot rules.

- convert LF to CRLF only outside start tags
- restore `
` alongside `
` so attribute values round-trip as read
- add a regression test: a Loxone-style file is byte-identical after one
  and two saves

Verified on a real 2.4MB project: a no-op save is byte-identical, and
`lox config layout --only-new` now changes only block coordinates.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant