Skip to content

[pull] develop from marktext:develop - #115

Merged
pull[bot] merged 6 commits into
code:developfrom
marktext:develop
Jul 5, 2026
Merged

[pull] develop from marktext:develop#115
pull[bot] merged 6 commits into
code:developfrom
marktext:develop

Conversation

@pull

@pull pull Bot commented Jul 5, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

Jocs and others added 6 commits July 5, 2026 08:04
…+ load) (#4861)

`loadLanguage` invoked Prism's `getLoader().load()` without a Promise
chainer, so the loader fired a dependent component's import without
awaiting its dependency. A component whose grammar extends another
(`cpp` extends `c`) could therefore evaluate before the dependency was
registered: `Prism.languages.extend('c', …)` ran on `undefined` and threw
"Cannot set properties of undefined (setting 'class-name')". That thrown
error also left the load promise unresolved, hanging the caller — which
surfaced as an intermittent 5s timeout in languageAlias.spec.ts on CI.

Pass Prism's `series`/`parallel` chainer (its documented `Promise#then` /
`Promise.all` hooks) so a dependency is imported and registered before its
dependent. Await the composed loader promise and collect statuses directly
instead of the ad-hoc deferred array (which only worked because the
no-chainer loader happened to invoke callbacks synchronously).

Reproduced the race locally (2/15 runs) and confirmed the fix eliminates it
(0/30); added loadLanguageDependencyOrder.spec.ts pinning the dependency
order (3/15 failing before the fix, deterministic after).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…th (CommonMark) (#4856)

* feat(muya): add firstWordOfInfo helper for code fence info strings

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(muya): make meta.lang hold the full code fence info string

Store the whole info string verbatim on meta.lang and serialize it as-is;
the language is derived as its first word. Removes the redundant meta.info
field and its staleness guard (the single field is now the source of truth).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(muya): derive code highlight language from the info string's first word

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(muya): let the code block language input edit the full info string

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(muya): centralize code fence language derivation (review cleanup)

Applies /simplify review feedback to the info-string refactor:

- Derive the highlight/tokenize language once in `CodeBlockContent._lang`
  (returns the info string's first word) instead of at each call site. This
  fixes two consumers the scattered approach missed — the tabHandler
  markup test and the Firefox-compat backspaceHandler both read the raw
  field and silently mis-derived the language for a multi-word info string.
- Move `firstWordOfInfo` from block/commonMark/codeBlock into utils, so the
  state layer no longer reaches into the block tree for it (removes a
  reverse state -> block runtime import).
- Simplify `lang: isFenced ? info : lang` to `lang: info` in
  `_buildCodeState` — indented blocks have no info string, so both arms are
  equal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
) (#4854)

The "/" quick-insert menu and the block "turn into" front menu labelled
their h1-h6 section "HEADERS" with items "Header 1".."Header 6". In
CommonMark/HTML terms those are headings; "header" means a page header or
front matter, so the wording was incorrect (only in English — the other
shipped locales already translated these as heading/title).

Rename the section (headers -> headings) and item titles (Header N ->
Heading N) in the menu config, and rename the matching i18n keys across
all locale files so every translation keeps resolving (their translated
values are unchanged). The internal block label ('atx-heading N') and
icon paths are untouched.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#4853)

The image-path auto-complete helper calls fs.watch() on the directory of
the path being typed, with no error handling. fs.watch throws
synchronously for directories the OS can't watch — notably UNC /
\\wsl.localhost network paths on Windows (EISDIR). The throw happened
inside the fs.readdir callback of searchFilesAndDir, so it escaped as an
uncaught exception and surfaced to the user as the generic "Unexpected
error occurred in the main process" dialog.

Wrap fs.watch in try/catch and attach an 'error' listener to the watcher
so auto-complete silently degrades to "not watching" that directory
instead of crashing the main process.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

* fix(desktop): save files atomically via temp-file + rename (#3786, #3828)

writeFile() wrote directly to the destination with fs-extra outputFile,
which truncates the existing file before streaming the new content. A
crash, BSOD, or power loss mid-write therefore left the user's document
truncated to 0 bytes (one report attached a 44393-byte file that was
entirely NUL). This is the data-loss the maintainers' own TODO in
writeMarkdownFile flagged as "safeSaveDocuments".

Write to a temp file in the same directory and rename it over the target
instead. The rename is atomic on a single volume (guaranteed by keeping
the temp file in the same directory), so an interrupted write can only
corrupt the throwaway temp file, never the existing document. outputFile
still recreates any missing parent directory first, preserving #3509.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(desktop): make the atomic save durable against power loss (#3786, #3828)

Addressing review: the temp-file + rename change fixed the application-crash
case but not the power-loss / OS-reboot case the issues actually describe. A
bare rename is namespace-atomic but not data-durable: after a power loss the
new directory entry can point at an inode whose data blocks were never
flushed — a full-length, zero-filled file, exactly the 44393-byte all-0x00
artifact in #3786. It also dropped the in-place write's mode/owner
preservation, symlink follow-through, and unique temp naming.

Delegate to write-file-atomic (fsync-before-rename), which closes the
power-loss window and restores those behaviors: it stat/chmod/chowns the
temp to match the target, writes through a symlink via realpath, and uses a
collision-free temp name. ensureDir keeps the #3509 missing-directory
behavior. Tests now cover overwrite/buffer/missing-dir and permission-mode
preservation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(desktop): type write-file-atomic via @types instead of a local shim

@types/write-file-atomic@4.0.3 declares the same public API write-file-atomic
7 exposes (its signature has been stable since v4), so drop the hand-rolled
module shim for it. Every writeFile caller passes a BufferEncoding or nothing,
so narrow the options parameter from WriteFileOptions to BufferEncoding — that
also sidesteps the Node Mode (string | number) vs @types mode (number)
mismatch cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… loss (#4864)

* build(desktop): add write-file-atomic dependency

Adds write-file-atomic (+ @types) for durable, atomic file writes. Used by
the crash-recovery buffer store; the document save path adopts it separately
in #4852.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(desktop): make crash-recovery buffer writes durable against power loss

writeBufferStoreFile persists unsaved tab content (the crash-recovery
buffer) with a temp-file + rename. That is namespace-atomic — safe against
an application crash — but omits fsync, so a power loss / OS reboot can
still commit the new directory entry while the data blocks were never
flushed, leaving a truncated or full-length zero-filled buffer. This is the
same gap the document save path had (#3786).

Write through write-file-atomic's sync API (fsync before the atomic rename),
which also removes the hand-rolled temp/rename/cleanup and the writeSequence
counter (its unique temp naming is handled internally).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators Jul 5, 2026
@pull pull Bot added the ⤵️ pull label Jul 5, 2026
@pull
pull Bot merged commit ac273f4 into code:develop Jul 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant