The single-instance check reads the pid of the running instance from
the "notepad--" shared memory and sends SIGUSR1 to it without any
validation. When the segment is left over from an abnormal exit the
stored pid can be 0, and kill(0, SIGUSR1) delivers SIGUSR1 (default
action: terminate) to the whole process group. Launched from the
desktop this kills the session processes and logs the user out. A
recycled pid may also cause an unrelated process to be killed.
Only signal the pid when it is > 1 and /proc/<pid>/comm matches our
own, otherwise start as a new instance. Also check the return value
of nppShared.attach() before dereferencing data().
The paragraph fallback checked the *previous* line before consuming the first line of a new paragraph. When renderQuote returned with i pointing right after a quote, the next line's prev started with '>', so the paragraph broke immediately without advancing i, and the outer loop spun on the same line forever -- freezing the whole UI.
Minimal repro (verified with a standalone harness, 3s watchdog per case): "> y\n<p>" -> HANG. The same trigger applies to headings / horizontal rules / fences followed directly by a non-blank line, e.g. "# T\ntext".
Fix: remember where the paragraph starts and only run the prev-based checks when continuing an existing paragraph (i > paraStart). A fresh paragraph always consumes its first line, so i always advances.
Also fixes a placeholder collision found while investigating: the hard line break marker was U+E001, inside the private-use range the inline stash allocates (0xE000..), so a hard break plus two inline code spans made the break marker get restored as a wrong stash slot (corrupted output, not a hang). Moved to U+0001, which escapeHtml passes through and which is replaced back before the HTML reaches setHtml.
Verified: standalone harness, 68 cases (HTML-heavy + regressions), all pass; previously-hanging inputs now render correctly.
Add a "Markdown Preview" action under the Tools menu that renders the current editor content and shows it in a separate window.
- src/mdrenderer.{h,cpp}: self-contained Markdown renderer (headings, nested lists, GFM tables, task lists, fenced code, blockquotes, links, images, hr). No third-party dependency.
- src/markdownview.{h,cpp}: add viewHtml() plus a style sheet applied via QTextDocument::setDefaultStyleSheet() so the preview is actually readable (heading hierarchy, code block background, table borders, quote blocks, document margin).
- src/cceditor/ccnotepad.{h,cpp}: add the menu action and the slot. The slot reads the current editor through ui.editTabWidget->currentWidget() and passes the text to MarkdownView.
- src/realcompare_zh.ts/.qm: Chinese translation so the menu reads "Markdown" when the UI language is Chinese.
Implemented inside the application rather than as a plugin: ScintillaEditView is defined in this module and ui.editTabWidget is a private member, so a plugin cannot obtain the current editor reliably across module boundaries.