diff --git a/rhino/text_editor.py b/rhino/text_editor.py index 9a7aeae..395e3bc 100644 --- a/rhino/text_editor.py +++ b/rhino/text_editor.py @@ -377,15 +377,14 @@ def _runs_to_rtf(runs, default_font, base_size_m=0.20): out.append("\\u{}?".format(v)) return "".join(out) - # Globales Newline-Tracking ueber ALLE Runs hinweg — ein `\n` - # zwischen Runs (= eigener Newline-Run) ergibt EINEN \\line. - # Mehrere aufeinanderfolgende `\n` ergeben entsprechend mehrere - # \\line in Reihe (= Leerzeile). + # Ansatz: jedes Text-Segment in eigene {}-Group mit lokalen Codes. + # Zwischen Segmenten (und ueber Run-Grenzen hinweg) \\par fuer + # Paragraph-Breaks. So bleibt Per-Run-Formatting (Groups isolieren + # State) UND Mehrzeiligkeit (\\par ist Rhinos echter Linebreak). body_parts = [] - pending_newlines = 0 # Newlines die noch emittiert werden muessen + pending_pars = 0 # Wieviele \\par muessen noch vor naechstem Segment - def _emit_text_segment(run, seg): - if not seg: return + def _emit_group(run, seg): codes = [] codes.append("\\f{}".format(font_idx(run.get("font") or default_font))) ci = color_idx(run.get("color")) if run.get("color") else 0 @@ -402,25 +401,29 @@ def _runs_to_rtf(runs, default_font, base_size_m=0.20): if run.get("sup"): codes.append("\\super") elif run.get("sub"): codes.append("\\sub") else: codes.append("\\nosupersub") - body_parts.append("{} {}".format("".join(codes), _escape_no_par(seg))) + body_parts.append("{{{} {}}}".format("".join(codes), _escape_no_par(seg))) + first_emitted = False for run in runs: raw = run.get("text") or "" - # Jede \n im Text → \\line; alle \\line werden VOR der naechsten - # Text-Section emittiert. Damit bleiben auch leere Zeilen erhalten. segments = raw.split("\n") for i, seg in enumerate(segments): if i > 0: - pending_newlines += 1 + pending_pars += 1 if seg: - # Pending Newlines emittieren bevor Text kommt - for _ in range(pending_newlines): - body_parts.append("\\line ") - pending_newlines = 0 - _emit_text_segment(run, seg) - # Trailing newlines auch noch emittieren - for _ in range(pending_newlines): - body_parts.append("\\line ") + # Pending \\par vor dem naechsten Inhalt — aber nur wenn + # schon mal Inhalt da war (sonst fuehrender \\par bringt + # Leerzeile am Anfang) + if first_emitted: + for _ in range(pending_pars): + body_parts.append("\\par ") + pending_pars = 0 + _emit_group(run, seg) + first_emitted = True + # Trailing \\par auch noch emittieren (= Leerzeilen am Ende) + if first_emitted: + for _ in range(pending_pars): + body_parts.append("\\par ") # ──────────────────────────────────────────────────────────────── # PASS 2: RTF-Header mit JETZT vollstaendigen Tables + Body