Previously, every streamed line triggered a full rebuild of the
block's HTML: reparsing all content, re-running syntax highlighting
on every code fence from the start. For a block with n lines this
was O(n) per line = O(n²) total.
Now appendContent() uses incrementalAppend() which:
- Prose: escapes only the new line and appends to the segment HTML
- Code fences: saves KSyntaxHighlighting::State between lines and
only highlights the new line (O(1) per line)
- Fence close: finalizes segment, requests diagrams as before
- Partial line display: uses cached state, no full re-highlight
Full rebuildBlockHtml() is retained only for diagram reply callbacks
where the entire segment needs reconstruction.
Also adds BlockRenderState to ChatBlock for tracking incremental
parse position, highlight state, and accumulated HTML.