VYPR
High severity7.1NVD Advisory· Published Jun 5, 2026· Updated Jun 8, 2026

CVE-2026-11422

CVE-2026-11422

Description

Markdown Preview Enhanced 0.8.x allows arbitrary JavaScript execution and file writes via crafted WaveDrom code blocks in its preview panel.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Markdown Preview Enhanced 0.8.x allows arbitrary JavaScript execution and file writes via crafted WaveDrom code blocks in its preview panel.

Vulnerability

Markdown Preview Enhanced versions 0.8.x, utilizing the crossnote engine version 0.9.28, contain a code injection vulnerability within the WaveDrom rendering pipeline. This vulnerability is triggered when a user opens a Markdown document containing a WaveDrom fenced code block and views it in the extension's preview panel. The content of this code block is passed unsanitized to window.eval() within the VS Code webview context [2]. The vulnerability exists due to the use of eval() instead of a safer parsing method like JSON.parse(), a bypass of sanitization layers, and the absence of an enableScriptExecution gate for WaveDrom rendering [2]. Affected versions include Markdown Preview Enhanced up to and including 0.8.27 and crossnote up to and including 0.9.28 [4].

Exploitation

An attacker needs to convince a user to open a specially crafted Markdown document within VS Code. This document must contain a WaveDrom fenced code block with malicious JavaScript content. When the user previews this document, the embedded JavaScript will be executed within the VS Code webview context. From this context, the attacker's code can access the vscodeApi object and use postMessage to invoke arbitrary file writes on the local filesystem [2].

Impact

Successful exploitation allows an attacker to execute arbitrary JavaScript within the VS Code webview context. This can lead to arbitrary file writes on the local filesystem, compromising the confidentiality, integrity, and potentially availability of the user's system. The vulnerability is characterized as Local (AV:L), with low attack complexity (AC:L), no privileges required (PR:N), and requires user interaction (UI:R) [4].

Mitigation

Markdown Preview Enhanced version 0.8.28, released on 2026-06-05, addresses this vulnerability by replacing eval() with JSON5.parse() for WaveDrom diagrams and improving the HTML sanitizer to validate WaveDrom data scripts [3]. The crossnote engine was updated to version 0.9.29 to include this fix [1]. Users are advised to update to Markdown Preview Enhanced 0.8.28 or later and crossnote 0.9.29 or later to mitigate this vulnerability [3].

AI Insight generated on Jun 8, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Patches

5
dcd80281c986

0.8.28 (#2318)

14 files changed · +1145 144
  • CHANGELOG.md+15 0 modified
    @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
     
     ## [Unreleased]
     
    +## [0.8.28] - 2026-06-05
    +
    +Updated [crossnote](https://github.com/shd101wyy/crossnote) to [0.9.29](https://github.com/shd101wyy/crossnote/releases/tag/0.9.29).
    +
    +### Bug fixes
    +
    +- **Harden external file/link opening against command injection** — Opening links and files from the preview no longer goes through a shell, and untrusted inputs (the diagram `filename` attribute, imported file paths, and the `latex_engine` code-chunk attribute) are passed as literal arguments or validated before use. This closes a security issue affecting Windows. Thanks to @byte16384 for the responsible disclosure.
    +- **Eliminate arbitrary code execution in WaveDrom rendering** — WaveDrom diagrams were parsed by evaluating untrusted markdown content with `eval()`, enabling arbitrary JavaScript execution. This affected every render path: the live preview (`window.eval`), and presentation mode plus HTML export (the bundled `WaveDrom.ProcessAll()`/`eva()` helpers). The live preview now parses with `JSON5.parse()`, and — because a malicious `<script type="WaveDrom">` can also be injected via raw HTML in markdown — the HTML sanitizer now validates and normalizes every WaveDrom data script to inert strict JSON, so no downstream `eval`/`ProcessAll` can execute attacker-controlled code. Fixes the security vulnerability reported in [#2315](https://github.com/shd101wyy/vscode-markdown-preview-enhanced/issues/2315).
    +- **Replace `interpretJS` with `JSON5.parse` in Bitfield renderer** — Bitfield fenced code blocks were parsed using `interpretJS()` which evaluates user input via `vm.runInNewContext`, enabling arbitrary code execution on the server side. Replaced with `JSON5.parse()` since bitfield register definitions are purely data (arrays of objects).
    +- **Improve MathJax 4 rendering performance** — MathJax 4's combined `tex-mml-chtml` component runs accessibility _semantic enrichment_ (the speech-rule-engine) on every typeset, which dominates per-formula cost and made formula-heavy previews re-render slowly on each edit (measured ~890 ms vs ~42 ms for 127 formulas in Chrome — a ~21× difference). Semantic enrichment is now disabled by default (`options.enableEnrichment: false`), restoring MathJax-3-like performance; users who need screen-reader speech output can set `enableEnrichment: true` in their `mathjaxConfig`. Addresses [#2312](https://github.com/shd101wyy/vscode-markdown-preview-enhanced/issues/2312).
    +
    +### Improvements
    +
    +- **Localized menus and settings (incl. Simplified Chinese)** — The bundled Simplified-Chinese translation shipped as `package.nls.zh.json`, but VS Code loads `package.nls.zh-cn.json`, so it never applied and menus stayed English; renamed so command/menu titles localize. In addition, all settings descriptions (and enum option descriptions) in the Settings UI — previously hardcoded English — are now localizable via VS Code's NLS mechanism and translated for every bundled display language (Simplified & Traditional Chinese, Japanese, Korean, Spanish, French, Brazilian Portuguese, Dutch, Turkish). Addresses [#2310](https://github.com/shd101wyy/vscode-markdown-preview-enhanced/issues/2310).
    +
     ## [0.8.27] - 2026-05-24
     
     Updated [crossnote](https://github.com/shd101wyy/crossnote) to [0.9.26](https://github.com/shd101wyy/crossnote/releases/tag/0.9.26) / [0.9.27](https://github.com/shd101wyy/crossnote/releases/tag/0.9.27) / [0.9.28](https://github.com/shd101wyy/crossnote/releases/tag/0.9.28).
    
  • package.json+100 100 modified
    @@ -1,7 +1,7 @@
     {
       "name": "markdown-preview-enhanced",
       "displayName": "%displayName%",
    -  "version": "0.8.27",
    +  "version": "0.8.28",
       "description": "%description%",
       "categories": [
         "Other"
    @@ -172,12 +172,12 @@
           "title": "Markdown Preview Enhanced",
           "properties": {
             "markdown-preview-enhanced.configPath": {
    -          "markdownDescription": "Restart is required after changes. The global configuration directory path. Leave it empty to use `$HOME/.crossnote` for Windows or `$XDG_CONFIG_HOME/.crossnote` or `$HOME/.local/state/crossnote` as the config path.",
    +          "markdownDescription": "%markdown-preview-enhanced.configPath.markdownDescription%",
               "default": "",
               "type": "string"
             },
             "markdown-preview-enhanced.markdownParser": {
    -          "description": "Markdown parser/renderer to use. 'markdown-it' (default) is the built-in renderer. 'pandoc' uses Pandoc (requires Pandoc installed; not available in VS Code web). 'markdown_yo' uses a high-performance WASM renderer (or native binary when markdownYoBinaryPath is set; experimental).",
    +          "description": "%markdown-preview-enhanced.markdownParser.description%",
               "default": "markdown-it",
               "type": "string",
               "enum": [
    @@ -186,35 +186,35 @@
                 "markdown_yo"
               ],
               "enumDescriptions": [
    -            "Built-in markdown-it renderer (default).",
    -            "Render via Pandoc. Requires Pandoc to be installed. Not available in VS Code web.",
    -            "High-performance renderer (experimental). Uses WASM by default, or a native binary when markdownYoBinaryPath is set. markdown-it is still used for token-based operations."
    +            "%markdown-preview-enhanced.markdownParser.enumDescriptions.0%",
    +            "%markdown-preview-enhanced.markdownParser.enumDescriptions.1%",
    +            "%markdown-preview-enhanced.markdownParser.enumDescriptions.2%"
               ]
             },
             "markdown-preview-enhanced.breakOnSingleNewLine": {
    -          "description": "In Markdown, a single newline character doesn't cause a line break in the generated HTML. In GitHub Flavored Markdown, that is not true. Enable this config option to insert line breaks in rendered HTML for single newlines in Markdown source.",
    +          "description": "%markdown-preview-enhanced.breakOnSingleNewLine.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.scrollSync": {
    -          "description": "Automatic scroll sync. This is now partially supported.",
    +          "description": "%markdown-preview-enhanced.scrollSync.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.liveUpdate": {
    -          "description": "Re-render the preview as the contents of the source changes, without requiring the source buffer to be saved. If disabled, the preview is re-rendered only when the buffer is saved to disk.",
    +          "description": "%markdown-preview-enhanced.liveUpdate.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.liveUpdateDebounceMs": {
    -          "description": "Debounce time in milliseconds for live updates. Higher values reduce CPU usage but may feel less responsive. Lower values provide more immediate feedback but may impact performance.",
    +          "description": "%markdown-preview-enhanced.liveUpdateDebounceMs.description%",
               "default": 300,
               "type": "number",
               "minimum": 0,
               "maximum": 5000
             },
             "markdown-preview-enhanced.previewMode": {
    -          "markdownDescription": "- **Single Preview**: Only one preview will be shown for all editors.\n- **Multiple Previews**: Multiple previews will be shown. Each editor has its own preview.\n- **Previews Only**: No editor will be shown. Only previews will be shown. You can use the in-preview editor to edit the markdown.\n\nRestart is required after changes.",
    +          "markdownDescription": "%markdown-preview-enhanced.previewMode.markdownDescription%",
               "type": "string",
               "enum": [
                 "Single Preview",
    @@ -224,12 +224,12 @@
               "default": "Single Preview"
             },
             "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited": {
    -          "description": "Automatically show preview of markdown being edited.",
    +          "description": "%markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.disableAutoPreviewForUriSchemes": {
    -          "markdownDescription": "A list of URI schemes (e.g., `vscode-notebook-cell`) to exclude from the `automaticallyShowPreviewOfMarkdownBeingEdited` feature. Files matching these schemes won't trigger the automatic preview.",
    +          "markdownDescription": "%markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription%",
               "default": [
                 "vscode-notebook-cell"
               ],
    @@ -239,7 +239,7 @@
               }
             },
             "markdown-preview-enhanced.disableAutoPreviewForFilePatterns": {
    -          "markdownDescription": "A list of file name patterns (e.g., `*.note.md`) to exclude from the `automaticallyShowPreviewOfMarkdownBeingEdited` feature. Files whose names match any of these patterns won't trigger the automatic preview. Supports `*` as a wildcard. Matching is performed against the file's basename (not full path) and is case-insensitive.",
    +          "markdownDescription": "%markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription%",
               "default": [],
               "type": "array",
               "items": {
    @@ -255,18 +255,18 @@
               ],
               "default": "selectedPreviewTheme",
               "markdownEnumDescriptions": [
    -            "Use the `markdown-preview-enhanced.previewTheme` setting.",
    -            "Follow system color scheme. If set to true, then the theme of markdown preview will automatically switch between light and dark when your system switch between light and dark. For example, if you set the current preview theme to `github-light.css`, then when your system is dark, the preview theme will be switched to `github-dark.css` automatically. If set to false, then the theme of markdown preview will not be changed automatically.",
    -            "Use the same theme as the editor (light or dark). If set to true, then the theme of markdown preview will automatically switch between light and dark when you switch between vscode light and dark theme. For example, if you set the current preview theme to `github-light.css`, then when you switch to vscode dark theme, the preview theme will be switched to `github-dark.css` automatically. If set to false, then the theme of markdown preview will not be changed automatically."
    +            "%markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0%",
    +            "%markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1%",
    +            "%markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2%"
               ]
             },
             "markdown-preview-enhanced.enableTypographer": {
    -          "description": "Enable smartypants and other sweet transforms.",
    +          "description": "%markdown-preview-enhanced.enableTypographer.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.mathRenderingOption": {
    -          "description": "Choose the Math expression rendering method here. You can also disable math rendering if you want by choosing 'None'.",
    +          "description": "%markdown-preview-enhanced.mathRenderingOption.description%",
               "default": "KaTeX",
               "type": "string",
               "enum": [
    @@ -276,7 +276,7 @@
               ]
             },
             "markdown-preview-enhanced.mathInlineDelimiters": {
    -          "description": "Use customized Math expression inline delimiters.",
    +          "description": "%markdown-preview-enhanced.mathInlineDelimiters.description%",
               "default": [
                 [
                   "$",
    @@ -290,7 +290,7 @@
               "type": "array"
             },
             "markdown-preview-enhanced.mathBlockDelimiters": {
    -          "description": "Use customized Math expression block delimiters.",
    +          "description": "%markdown-preview-enhanced.mathBlockDelimiters.description%",
               "default": [
                 [
                   "$$",
    @@ -304,7 +304,7 @@
               "type": "array"
             },
             "markdown-preview-enhanced.mathRenderingOnlineService": {
    -          "description": "Choose the Math expression rendering method option for GFM markdown export (Save as Markdown).",
    +          "description": "%markdown-preview-enhanced.mathRenderingOnlineService.description%",
               "default": "https://latex.codecogs.com/gif.latex",
               "type": "string",
               "enum": [
    @@ -314,7 +314,7 @@
               ]
             },
             "markdown-preview-enhanced.mathjaxScriptSrc": {
    -          "description": "MathJax script source. Leave it empty to use the default CDN (MathJax v4).",
    +          "description": "%markdown-preview-enhanced.mathjaxScriptSrc.description%",
               "default": "https://cdn.jsdelivr.net/npm/mathjax@4/tex-mml-chtml.js",
               "type": "string"
             },
    @@ -324,53 +324,53 @@
               "type": "string"
             },
             "markdown-preview-enhanced.enableWikiLinkSyntax": {
    -          "description": "Enable Wiki Link syntax support. More information can be found at https://help.github.com/articles/adding-links-to-wikis/",
    +          "description": "%markdown-preview-enhanced.enableWikiLinkSyntax.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.enableLinkify": {
    -          "description": "Enable or disable conversion of URL-like text to links in the markdown preview.",
    +          "description": "%markdown-preview-enhanced.enableLinkify.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.useGitHubStylePipedLink": {
    -          "description": "If checked, we use GitHub style piped wiki links, i.e. [[linkText|wikiLink]]. Otherwise, we use [[wikiLink|linkText]] as the original Wikipedia style.",
    +          "description": "%markdown-preview-enhanced.useGitHubStylePipedLink.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.enableEmojiSyntax": {
    -          "description": "Enable emoji & font-awesome plugin. This only works for markdown-it parser, but not pandoc parser.",
    +          "description": "%markdown-preview-enhanced.enableEmojiSyntax.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.enableExtendedTableSyntax": {
    -          "description": "Enable extended table syntax to support merging table cells.",
    +          "description": "%markdown-preview-enhanced.enableExtendedTableSyntax.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.enableCriticMarkupSyntax": {
    -          "description": "Enable CriticMarkup syntax. Only works with markdown-it parser. Please check http://criticmarkup.com/users-guide.php for more information.",
    +          "description": "%markdown-preview-enhanced.enableCriticMarkupSyntax.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.enableTagSyntax": {
    -          "description": "Enable Obsidian-style #tag syntax. Renders `#tag-name` (and nested `#parent/child`) as clickable pill-shaped anchors. Click a tag to open VS Code's \"Search in Files\" pre-filled with the tag.",
    +          "description": "%markdown-preview-enhanced.enableTagSyntax.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.maxNoteFileSize": {
    -          "markdownDescription": "Maximum size (in bytes) of a Markdown file that crossnote will load into the in-memory note index. Files larger than the cap are skipped during workspace refresh — they won't appear in autocomplete, backlinks, or the tag panel, but you can still open them via wikilink click. Prevents pathological cases where a checked-in log/data dump with a `.md` extension would otherwise pin its full content (plus a parsed token tree) in memory. Set to `0` to disable the cap.",
    +          "markdownDescription": "%markdown-preview-enhanced.maxNoteFileSize.markdownDescription%",
               "default": 5242880,
               "type": "number",
               "minimum": 0
             },
             "markdown-preview-enhanced.wikiLinkTargetFileExtension": {
    -          "markdownDescription": "The file extension for the link in wikilink if the link does not have an extension.",
    +          "markdownDescription": "%markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription%",
               "default": ".md",
               "type": "string"
             },
             "markdown-preview-enhanced.wikiLinkResolution": {
    -          "markdownDescription": "How bare-filename wiki links (e.g. `[[Note]]`) are resolved to a file path.\n\n- `relative` — resolve relative to the current note's directory (default).\n- `shortest` — search all notes by filename, preferring the shortest unique path (with same-directory tiebreaking). Obsidian-style.\n- `absolute` — resolve from the notebook/workspace root.\n\nLinks starting with `/` always resolve from the notebook root regardless of this setting.",
    +          "markdownDescription": "%markdown-preview-enhanced.wikiLinkResolution.markdownDescription%",
               "default": "relative",
               "type": "string",
               "enum": [
    @@ -379,13 +379,13 @@
                 "absolute"
               ],
               "enumDescriptions": [
    -            "Resolve relative to the current note's directory.",
    -            "Search all notes by filename, preferring the shortest unique path.",
    -            "Resolve from the notebook/workspace root."
    +            "%markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0%",
    +            "%markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1%",
    +            "%markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2%"
               ]
             },
             "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase": {
    -          "markdownDescription": "The case for the file name in wikilink. If the value is `none`, then the file name will not be changed. Otherwise, the file name will be transformed to the specified case. You can read https://www.npmjs.com/package/case-anything for more details.",
    +          "markdownDescription": "%markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription%",
               "default": "none",
               "type": "string",
               "enum": [
    @@ -407,7 +407,7 @@
               ]
             },
             "markdown-preview-enhanced.frontMatterRenderingOption": {
    -          "description": "Front matter rendering option",
    +          "description": "%markdown-preview-enhanced.frontMatterRenderingOption.description%",
               "type": "string",
               "enum": [
                 "none",
    @@ -417,7 +417,7 @@
               "default": "none"
             },
             "markdown-preview-enhanced.mermaidTheme": {
    -          "description": "Mermaid theme, you can choose one from [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"]",
    +          "description": "%markdown-preview-enhanced.mermaidTheme.description%",
               "default": "default",
               "type": "string",
               "enum": [
    @@ -427,7 +427,7 @@
               ]
             },
             "markdown-preview-enhanced.codeBlockTheme": {
    -          "description": "Code block theme. If `auto.css` is chosen, then the code block theme that best matches the current preview theme will be picked.",
    +          "description": "%markdown-preview-enhanced.codeBlockTheme.description%",
               "default": "auto.css",
               "type": "string",
               "enum": [
    @@ -459,7 +459,7 @@
               ]
             },
             "markdown-preview-enhanced.previewTheme": {
    -          "description": "Preview Theme",
    +          "description": "%markdown-preview-enhanced.previewTheme.description%",
               "default": "github-light.css",
               "type": "string",
               "enum": [
    @@ -482,27 +482,27 @@
                 "vue.css"
               ],
               "markdownEnumDescriptions": [
    -            "Atom Dark",
    -            "Atom Light",
    -            "Atom Material",
    -            "GitHub Dark",
    -            "GitHub Light",
    -            "Gothic",
    -            "Medium",
    -            "Monokai",
    -            "Newsprint",
    -            "Night",
    -            "None",
    -            "One Dark",
    -            "One Light",
    -            "Solarized Dark",
    -            "Solarized Light",
    -            "VS Code",
    -            "Vue"
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15%",
    +            "%markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16%"
               ]
             },
             "markdown-preview-enhanced.revealjsTheme": {
    -          "description": "RevealJS Presentation Theme",
    +          "description": "%markdown-preview-enhanced.revealjsTheme.description%",
               "default": "white.css",
               "type": "string",
               "enum": [
    @@ -522,17 +522,17 @@
               ]
             },
             "markdown-preview-enhanced.protocolsWhiteList": {
    -          "description": "Accepted protocols for links.",
    +          "description": "%markdown-preview-enhanced.protocolsWhiteList.description%",
               "default": "http://, https://, atom://, file://, mailto:, tel:",
               "type": "string"
             },
             "markdown-preview-enhanced.imageFolderPath": {
    -          "description": "When using Image Helper to copy images, by default images will be copied to root image folder path '/assets'",
    +          "description": "%markdown-preview-enhanced.imageFolderPath.description%",
               "default": "/assets",
               "type": "string"
             },
             "markdown-preview-enhanced.imageUploader": {
    -          "description": "You can choose different image uploader to upload image",
    +          "description": "%markdown-preview-enhanced.imageUploader.description%",
               "default": "imgur",
               "type": "string",
               "enum": [
    @@ -544,155 +544,155 @@
             "markdown-preview-enhanced.qiniuAccessKey": {
               "type": "string",
               "default": "",
    -          "description": "Qiniu AccessKey"
    +          "description": "%markdown-preview-enhanced.qiniuAccessKey.description%"
             },
             "markdown-preview-enhanced.qiniuSecretKey": {
               "type": "string",
               "default": "",
    -          "description": "Qiniu SecretKey"
    +          "description": "%markdown-preview-enhanced.qiniuSecretKey.description%"
             },
             "markdown-preview-enhanced.qiniuBucket": {
               "type": "string",
               "default": "",
    -          "description": "Qiniu Bucket"
    +          "description": "%markdown-preview-enhanced.qiniuBucket.description%"
             },
             "markdown-preview-enhanced.qiniuDomain": {
               "type": "string",
               "default": "http://",
    -          "description": "Qiniu Domain"
    +          "description": "%markdown-preview-enhanced.qiniuDomain.description%"
             },
             "markdown-preview-enhanced.printBackground": {
    -          "description": "Whether to print background for file export or not. If set to `false`, then `github-light` preview theme will be used. You can also set `print_background` in front-matter for individual files.",
    +          "description": "%markdown-preview-enhanced.printBackground.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.chromePath": {
    -          "description": "Chrome executable path, which is used for Puppeteer export. Leaving it empty means the path will be found automatically.",
    +          "description": "%markdown-preview-enhanced.chromePath.description%",
               "default": "",
               "type": "string",
               "scope": "machine"
             },
             "markdown-preview-enhanced.imageMagickPath": {
    -          "description": "ImageMagick command line path. Should be either `magick` or `convert`. Leaving it empty means the path will be found automatically.",
    +          "description": "%markdown-preview-enhanced.imageMagickPath.description%",
               "default": "",
               "type": "string",
               "scope": "machine"
             },
             "markdown-preview-enhanced.pandocPath": {
    -          "description": "Pandoc executable path",
    +          "description": "%markdown-preview-enhanced.pandocPath.description%",
               "default": "pandoc",
               "type": "string",
               "scope": "machine"
             },
             "markdown-preview-enhanced.markdownYoBinaryPath": {
    -          "description": "Path to the markdown_yo native binary. When set and markdownParser is 'markdown_yo', crossnote will use this binary (via stdin/stdout) instead of the bundled WASM module. The native binary is faster for files under ~300 KB; WASM is faster for very large files. Supports $HOME and ~ variable substitution. Leave empty to use WASM (default).",
    +          "description": "%markdown-preview-enhanced.markdownYoBinaryPath.description%",
               "default": "",
               "type": "string",
               "scope": "machine"
             },
             "markdown-preview-enhanced.pandocMarkdownFlavor": {
    -          "description": "The pandoc markdown flavor you want",
    +          "description": "%markdown-preview-enhanced.pandocMarkdownFlavor.description%",
               "default": "markdown-raw_tex+tex_math_single_backslash",
               "type": "string"
             },
             "markdown-preview-enhanced.pandocArguments": {
    -          "description": "Args passed to pandoc command e.g. [\"--smart\", \"--filter=/bin/exe\"] Please use long argument names.",
    +          "description": "%markdown-preview-enhanced.pandocArguments.description%",
               "default": [],
               "type": "array"
             },
             "markdown-preview-enhanced.latexEngine": {
    -          "description": "Default latex engine for Pandoc export and latex code chunk.",
    +          "description": "%markdown-preview-enhanced.latexEngine.description%",
               "default": "pdflatex",
               "type": "string"
             },
             "markdown-preview-enhanced.enableScriptExecution": {
    -          "description": "Enables executing code chunks and importing javascript files.\n⚠️ Please use this feature with caution because it may put your security at risk! Your machine can get hacked if someone makes you open a markdown with malicious code while script execution is enabled.",
    +          "description": "%markdown-preview-enhanced.enableScriptExecution.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.enableHTML5Embed": {
    -          "description": " Enables transform audio video link to to html5 embed audio video tags.",
    +          "description": "%markdown-preview-enhanced.enableHTML5Embed.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.HTML5EmbedUseImageSyntax": {
    -          "description": " Enables video/audio embed with ![]() syntax (default).",
    +          "description": "%markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax": {
    -          "description": "Enables video/audio embed with []() syntax.",
    +          "description": "%markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp": {
    -          "description": "When true embed media with http:// schema in URLs. When false ignore and don't embed them.",
    +          "description": "%markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.HTML5EmbedAudioAttributes": {
    -          "description": "HTML attributes to pass to audio tags.",
    +          "description": "%markdown-preview-enhanced.HTML5EmbedAudioAttributes.description%",
               "default": "controls preload=\"metadata\" width=\"320\"",
               "type": "string"
             },
             "markdown-preview-enhanced.HTML5EmbedVideoAttributes": {
    -          "description": "HTML attributes to pass to video tags.",
    +          "description": "%markdown-preview-enhanced.HTML5EmbedVideoAttributes.description%",
               "default": "controls preload=\"metadata\" width=\"320\" height=\"240\"",
               "type": "string"
             },
             "markdown-preview-enhanced.puppeteerWaitForTimeout": {
    -          "description": "Puppeteer waits for a certain timeout in milliseconds before the document export.",
    +          "description": "%markdown-preview-enhanced.puppeteerWaitForTimeout.description%",
               "default": 0,
               "type": "number"
             },
             "markdown-preview-enhanced.puppeteerArgs": {
    -          "description": "Args passed to puppeteer.launch({args: $puppeteerArgs})",
    +          "description": "%markdown-preview-enhanced.puppeteerArgs.description%",
               "default": [],
               "type": "array"
             },
             "markdown-preview-enhanced.plantumlServer": {
    -          "description": "Render using PlantUML server instead of binary. Leave it empty to use the builtin plantuml.jar binary (`java` is required in system path). Eg: \"http://localhost:8080/svg/\"",
    +          "description": "%markdown-preview-enhanced.plantumlServer.description%",
               "default": "",
               "type": "string"
             },
             "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons": {
    -          "description": "Hide the default VSCode markdown preview extension buttons. Restarting the editor is required to make this config take effect.",
    +          "description": "%markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.jsdelivrCdnHost": {
    -          "markdownDescription": "jsDelivr CDN host. Example values: `cdn.jsdelivr.net`, `fastly.jsdelivr.net`, `gcore.jsdelivr.net`, `testingcf.jsdelivr.net`",
    +          "markdownDescription": "%markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription%",
               "default": "cdn.jsdelivr.net",
               "type": "string"
             },
             "markdown-preview-enhanced.plantumlJarPath": {
    -          "description": "Absolute path to the plantuml.jar file (`java` is required in system path). You can download it from https://plantuml.com/download.",
    +          "description": "%markdown-preview-enhanced.plantumlJarPath.description%",
               "default": "",
               "type": "string"
             },
             "markdown-preview-enhanced.krokiServer": {
    -          "description": "The URL of the Kroki server to use.  ",
    +          "description": "%markdown-preview-enhanced.krokiServer.description%",
               "default": "https://kroki.io",
               "type": "string"
             },
             "markdown-preview-enhanced.webSequenceDiagramsServer": {
    -          "description": "The URL of the WebSequenceDiagrams server to use for rendering wsd code blocks.",
    +          "description": "%markdown-preview-enhanced.webSequenceDiagramsServer.description%",
               "default": "https://www.websequencediagrams.com",
               "type": "string"
             },
             "markdown-preview-enhanced.webSequenceDiagramsApiKey": {
    -          "description": "API key for WebSequenceDiagrams. Required for wider diagram sizes.",
    +          "description": "%markdown-preview-enhanced.webSequenceDiagramsApiKey.description%",
               "default": "",
               "type": "string"
             },
             "markdown-preview-enhanced.d2Path": {
    -          "description": "Path to the D2 executable. Defaults to `d2` (i.e. found on PATH). Not supported in the web extension.",
    +          "description": "%markdown-preview-enhanced.d2Path.description%",
               "default": "d2",
               "type": "string",
               "scope": "machine"
             },
             "markdown-preview-enhanced.d2Layout": {
    -          "description": "Default D2 layout engine for rendering d2 diagrams.",
    +          "description": "%markdown-preview-enhanced.d2Layout.description%",
               "default": "dagre",
               "type": "string",
               "enum": [
    @@ -702,7 +702,7 @@
               ]
             },
             "markdown-preview-enhanced.d2Theme": {
    -          "description": "Default D2 theme for rendering d2 diagrams.",
    +          "description": "%markdown-preview-enhanced.d2Theme.description%",
               "default": 0,
               "type": "number",
               "enum": [
    @@ -751,12 +751,12 @@
               ]
             },
             "markdown-preview-enhanced.d2Sketch": {
    -          "description": "Render D2 diagrams in sketch (hand-drawn) style.",
    +          "description": "%markdown-preview-enhanced.d2Sketch.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.markdownFileExtensions": {
    -          "description": "Markdown file extensions. This is used to determine whether to show the preview button in the markdown file context menu.",
    +          "description": "%markdown-preview-enhanced.markdownFileExtensions.description%",
               "default": [
                 ".md",
                 ".markdown",
    @@ -770,22 +770,22 @@
               "type": "array"
             },
             "markdown-preview-enhanced.alwaysShowBacklinksInPreview": {
    -          "description": "Always show backlinks in preview.",
    +          "description": "%markdown-preview-enhanced.alwaysShowBacklinksInPreview.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.enablePreviewZenMode": {
    -          "description": "Enable this option will hide unnecessary UI elements in preview unless your mouse is over it.",
    +          "description": "%markdown-preview-enhanced.enablePreviewZenMode.description%",
               "default": true,
               "type": "boolean"
             },
             "markdown-preview-enhanced.useVSCodeThemeForContextMenu": {
    -          "description": "When enabled, the context menu in preview inherits VS Code's theme colors and font instead of the default styling.",
    +          "description": "%markdown-preview-enhanced.useVSCodeThemeForContextMenu.description%",
               "default": false,
               "type": "boolean"
             },
             "markdown-preview-enhanced.enableImageLightbox": {
    -          "description": "Click an image in the preview to view it in a full-screen lightbox overlay. Press Escape or click the backdrop to close.",
    +          "description": "%markdown-preview-enhanced.enableImageLightbox.description%",
               "default": true,
               "type": "boolean"
             }
    @@ -890,7 +890,7 @@
         "@types/crypto-js": "^4.1.2",
         "@types/vfile": "^3.0.2",
         "async-mutex": "^0.4.0",
    -    "crossnote": "^0.9.28",
    +    "crossnote": "0.9.29",
         "crypto-js": "^4.2.0"
       },
       "devDependencies": {
    
  • package.nls.es.json+99 1 modified
    @@ -27,5 +27,103 @@
       "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:Extender analizador (Área de trabajo)",
       "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:Personalizar encabezado HTML (Global)",
       "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:Personalizar encabezado HTML (Área de trabajo)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Mostrar imágenes subidas"
    +  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Mostrar imágenes subidas",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "Se requiere reiniciar después de los cambios. Ruta del directorio de configuración global. Déjelo vacío para usar `$HOME/.crossnote` en Windows, o `$XDG_CONFIG_HOME/.crossnote` o `$HOME/.local/state/crossnote` como ruta de configuración.",
    +  "markdown-preview-enhanced.markdownParser.description": "Analizador/renderizador de Markdown que se usará. 'markdown-it' (predeterminado) es el renderizador integrado. 'pandoc' usa Pandoc (requiere Pandoc instalado; no disponible en VS Code web). 'markdown_yo' usa un renderizador WASM de alto rendimiento (o un binario nativo cuando se define markdownYoBinaryPath; experimental).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "Renderizador markdown-it integrado (predeterminado).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "Renderiza con Pandoc. Requiere que Pandoc esté instalado. No disponible en VS Code web.",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "Renderizador de alto rendimiento (experimental). Usa WASM de forma predeterminada, o un binario nativo cuando se define markdownYoBinaryPath. markdown-it se sigue usando para las operaciones basadas en tokens.",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "En Markdown, un único carácter de salto de línea no produce un salto de línea en el HTML generado. En GitHub Flavored Markdown no es así. Active esta opción para insertar saltos de línea en el HTML renderizado por cada salto de línea único en el origen de Markdown.",
    +  "markdown-preview-enhanced.scrollSync.description": "Sincronización automática del desplazamiento. Actualmente tiene compatibilidad parcial.",
    +  "markdown-preview-enhanced.liveUpdate.description": "Vuelve a renderizar la vista previa a medida que cambia el contenido del origen, sin necesidad de guardar el búfer de origen. Si se desactiva, la vista previa solo se vuelve a renderizar cuando el búfer se guarda en disco.",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "Tiempo de antirrebote en milisegundos para las actualizaciones en vivo. Valores más altos reducen el uso de CPU pero pueden parecer menos receptivos. Valores más bajos ofrecen una respuesta más inmediata pero pueden afectar al rendimiento.",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview**: solo se muestra una vista previa para todos los editores.\n- **Multiple Previews**: se muestran varias vistas previas. Cada editor tiene su propia vista previa.\n- **Previews Only**: no se muestra ningún editor. Solo se muestran las vistas previas. Puede usar el editor dentro de la vista previa para editar el Markdown.\n\nSe requiere reiniciar después de los cambios.",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "Mostrar automáticamente la vista previa del Markdown que se está editando.",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "Lista de esquemas URI (por ejemplo, `vscode-notebook-cell`) que se excluirán de la función `automaticallyShowPreviewOfMarkdownBeingEdited`. Los archivos que coincidan con estos esquemas no activarán la vista previa automática.",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "Lista de patrones de nombre de archivo (por ejemplo, `*.note.md`) que se excluirán de la función `automaticallyShowPreviewOfMarkdownBeingEdited`. Los archivos cuyo nombre coincida con alguno de estos patrones no activarán la vista previa automática. Admite `*` como comodín. La coincidencia se realiza sobre el nombre base del archivo (no la ruta completa) y no distingue mayúsculas de minúsculas.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "Usar la opción `markdown-preview-enhanced.previewTheme`.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "Seguir el esquema de color del sistema. Si se establece en true, el tema de la vista previa de Markdown cambiará automáticamente entre claro y oscuro cuando el sistema cambie entre claro y oscuro. Por ejemplo, si el tema de vista previa actual es `github-light.css`, cuando el sistema esté en oscuro, el tema de la vista previa cambiará automáticamente a `github-dark.css`. Si se establece en false, el tema de la vista previa no cambiará automáticamente.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "Usar el mismo tema que el editor (claro u oscuro). Si se establece en true, el tema de la vista previa de Markdown cambiará automáticamente entre claro y oscuro cuando cambie entre el tema claro y oscuro de VS Code. Por ejemplo, si el tema de vista previa actual es `github-light.css`, al cambiar al tema oscuro de VS Code, el tema de la vista previa cambiará automáticamente a `github-dark.css`. Si se establece en false, el tema de la vista previa no cambiará automáticamente.",
    +  "markdown-preview-enhanced.enableTypographer.description": "Activar smartypants y otras transformaciones tipográficas.",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "Elija aquí el método de renderizado de expresiones matemáticas. También puede desactivar el renderizado de matemáticas eligiendo 'None'.",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "Usar delimitadores personalizados para expresiones matemáticas en línea.",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "Usar delimitadores personalizados para bloques de expresiones matemáticas.",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "Elija el método de renderizado de expresiones matemáticas para la exportación de Markdown GFM (Guardar como Markdown).",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "Origen del script de MathJax. Déjelo vacío para usar la CDN predeterminada (MathJax v4).",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "Activar la compatibilidad con la sintaxis de enlaces Wiki. Encontrará más información en https://help.github.com/articles/adding-links-to-wikis/",
    +  "markdown-preview-enhanced.enableLinkify.description": "Activar o desactivar la conversión de texto similar a URL en enlaces en la vista previa de Markdown.",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "Si se marca, usamos enlaces Wiki con barra vertical al estilo de GitHub, es decir, [[linkText|wikiLink]]. De lo contrario, usamos [[wikiLink|linkText]] al estilo original de Wikipedia.",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "Activar el complemento de emoji y font-awesome. Esto solo funciona con el analizador markdown-it, no con el analizador pandoc.",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "Activar la sintaxis de tablas extendida para admitir la combinación de celdas.",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "Activar la sintaxis CriticMarkup. Solo funciona con el analizador markdown-it. Consulte http://criticmarkup.com/users-guide.php para más información.",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "Activar la sintaxis de etiquetas #tag al estilo de Obsidian. Renderiza `#tag-name` (y los anidados `#parent/child`) como anclas con forma de píldora en las que se puede hacer clic. Haga clic en una etiqueta para abrir «Buscar en archivos» de VS Code con la etiqueta ya rellenada.",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "Tamaño máximo (en bytes) de un archivo Markdown que crossnote cargará en el índice de notas en memoria. Los archivos que superen el límite se omiten durante la actualización del área de trabajo: no aparecerán en el autocompletado, los backlinks ni el panel de etiquetas, pero aún podrá abrirlos haciendo clic en un enlace wiki. Evita los casos patológicos en los que un volcado de registros/datos con extensión `.md` mantendría todo su contenido (más un árbol de tokens analizado) en memoria. Establézcalo en `0` para desactivar el límite.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "La extensión de archivo para el enlace de un enlace wiki si el enlace no tiene extensión.",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "Cómo se resuelven a una ruta de archivo los enlaces wiki con solo el nombre de archivo (p. ej. `[[Note]]`).\n\n- `relative`: se resuelve en relación con el directorio de la nota actual (predeterminado).\n- `shortest`: busca en todas las notas por nombre de archivo, prefiriendo la ruta única más corta (con desempate en el mismo directorio). Al estilo de Obsidian.\n- `absolute`: se resuelve desde la raíz del cuaderno/área de trabajo.\n\nLos enlaces que comienzan con `/` siempre se resuelven desde la raíz del cuaderno, independientemente de esta opción.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "Se resuelve en relación con el directorio de la nota actual.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "Busca en todas las notas por nombre de archivo, prefiriendo la ruta única más corta.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "Se resuelve desde la raíz del cuaderno/área de trabajo.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "El uso de mayúsculas/minúsculas para el nombre de archivo en un enlace wiki. Si el valor es `none`, el nombre de archivo no se modifica. De lo contrario, el nombre de archivo se transformará al formato especificado. Puede leer https://www.npmjs.com/package/case-anything para más detalles.",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Opción de renderizado del front matter",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Tema de Mermaid; puede elegir uno de [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"]",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "Tema de los bloques de código. Si se elige `auto.css`, se seleccionará el tema de bloque de código que mejor coincida con el tema de vista previa actual.",
    +  "markdown-preview-enhanced.previewTheme.description": "Tema de la vista previa",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "Ninguno",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "Tema de presentación de RevealJS",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "Protocolos aceptados para los enlaces.",
    +  "markdown-preview-enhanced.imageFolderPath.description": "Al usar el Asistente de imágenes para copiar imágenes, de forma predeterminada las imágenes se copiarán a la ruta de la carpeta de imágenes raíz '/assets'",
    +  "markdown-preview-enhanced.imageUploader.description": "Puede elegir distintos servicios para subir imágenes",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "Qiniu AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "Qiniu SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "Qiniu Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "Qiniu Domain",
    +  "markdown-preview-enhanced.printBackground.description": "Si se imprime o no el fondo al exportar archivos. Si se establece en `false`, se usará el tema de vista previa `github-light`. También puede establecer `print_background` en el front-matter de archivos concretos.",
    +  "markdown-preview-enhanced.chromePath.description": "Ruta del ejecutable de Chrome, que se usa para la exportación con Puppeteer. Dejarlo vacío significa que la ruta se buscará automáticamente.",
    +  "markdown-preview-enhanced.imageMagickPath.description": "Ruta de la línea de comandos de ImageMagick. Debe ser `magick` o `convert`. Dejarlo vacío significa que la ruta se buscará automáticamente.",
    +  "markdown-preview-enhanced.pandocPath.description": "Ruta del ejecutable de Pandoc",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "Ruta del binario nativo de markdown_yo. Cuando se define y markdownParser es 'markdown_yo', crossnote usará este binario (mediante stdin/stdout) en lugar del módulo WASM integrado. El binario nativo es más rápido para archivos de menos de ~300 KB; WASM es más rápido para archivos muy grandes. Admite la sustitución de las variables $HOME y ~. Déjelo vacío para usar WASM (predeterminado).",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "La variante de Markdown de Pandoc que desea",
    +  "markdown-preview-enhanced.pandocArguments.description": "Argumentos pasados al comando pandoc, p. ej. [\"--smart\", \"--filter=/bin/exe\"]. Use nombres de argumento largos.",
    +  "markdown-preview-enhanced.latexEngine.description": "Motor de latex predeterminado para la exportación con Pandoc y los bloques de código latex.",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "Activa la ejecución de bloques de código y la importación de archivos JavaScript.\n⚠️ Use esta función con precaución, ya que puede poner en riesgo su seguridad. Su equipo podría verse comprometido si alguien le hace abrir un Markdown con código malicioso mientras la ejecución de scripts está activada.",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": "Activa la transformación de enlaces de audio y vídeo en etiquetas de audio y vídeo embebidas de HTML5.",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": "Activa la inserción de vídeo/audio con la sintaxis ![]() (predeterminado).",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "Activa la inserción de vídeo/audio con la sintaxis []().",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "Si es true, inserta medios con el esquema http:// en las URL. Si es false, los ignora y no los inserta.",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "Atributos HTML que se pasan a las etiquetas de audio.",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "Atributos HTML que se pasan a las etiquetas de vídeo.",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "Puppeteer espera un tiempo de espera determinado en milisegundos antes de exportar el documento.",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "Argumentos pasados a puppeteer.launch({args: $puppeteerArgs})",
    +  "markdown-preview-enhanced.plantumlServer.description": "Renderizar usando un servidor de PlantUML en lugar del binario. Déjelo vacío para usar el binario plantuml.jar integrado (se requiere `java` en la ruta del sistema). Ej.: \"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "Ocultar los botones de la extensión de vista previa de Markdown predeterminada de VS Code. Es necesario reiniciar el editor para que esta opción surta efecto.",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "Host de la CDN de jsDelivr. Valores de ejemplo: `cdn.jsdelivr.net`, `fastly.jsdelivr.net`, `gcore.jsdelivr.net`, `testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "Ruta absoluta al archivo plantuml.jar (se requiere `java` en la ruta del sistema). Puede descargarlo desde https://plantuml.com/download.",
    +  "markdown-preview-enhanced.krokiServer.description": "La URL del servidor de Kroki que se usará.",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "La URL del servidor de WebSequenceDiagrams que se usará para renderizar los bloques de código wsd.",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "Clave de API para WebSequenceDiagrams. Necesaria para tamaños de diagrama más grandes.",
    +  "markdown-preview-enhanced.d2Path.description": "Ruta del ejecutable de D2. De forma predeterminada `d2` (es decir, que esté en el PATH). No se admite en la extensión web.",
    +  "markdown-preview-enhanced.d2Layout.description": "Motor de diseño D2 predeterminado para renderizar diagramas d2.",
    +  "markdown-preview-enhanced.d2Theme.description": "Tema D2 predeterminado para renderizar diagramas d2.",
    +  "markdown-preview-enhanced.d2Sketch.description": "Renderizar los diagramas D2 con estilo de boceto (dibujado a mano).",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Extensiones de archivo de Markdown. Se usa para determinar si se muestra el botón de vista previa en el menú contextual de los archivos Markdown.",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "Mostrar siempre los backlinks en la vista previa.",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "Al activar esta opción se ocultarán los elementos de interfaz innecesarios en la vista previa, salvo cuando el ratón esté sobre ellos.",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "Cuando está activado, el menú contextual de la vista previa hereda los colores y la fuente del tema de VS Code en lugar del estilo predeterminado.",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "Haga clic en una imagen de la vista previa para verla en una superposición de lightbox a pantalla completa. Pulse Escape o haga clic en el fondo para cerrar."
     }
    
  • package.nls.fr.json+99 1 modified
    @@ -27,5 +27,103 @@
       "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:Étendre le parseur (Espace de travail)",
       "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:Personnaliser l'en-tête HTML de l'aperçu (Global)",
       "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:Personnaliser l'en-tête HTML de l'aperçu (Espace de travail)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Afficher les images téléchargées"
    +  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Afficher les images téléchargées",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "Un redémarrage est requis après modification. Chemin du répertoire de configuration global. Laissez-le vide pour utiliser `$HOME/.crossnote` sous Windows, ou `$XDG_CONFIG_HOME/.crossnote` ou `$HOME/.local/state/crossnote` comme chemin de configuration.",
    +  "markdown-preview-enhanced.markdownParser.description": "Analyseur/moteur de rendu Markdown à utiliser. 'markdown-it' (par défaut) est le moteur de rendu intégré. 'pandoc' utilise Pandoc (nécessite l'installation de Pandoc ; non disponible dans VS Code web). 'markdown_yo' utilise un moteur de rendu WASM performant (ou un binaire natif lorsque markdownYoBinaryPath est défini ; expérimental).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "Moteur de rendu markdown-it intégré (par défaut).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "Rendu via Pandoc. Nécessite l'installation de Pandoc. Non disponible dans VS Code web.",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "Moteur de rendu performant (expérimental). Utilise WASM par défaut, ou un binaire natif lorsque markdownYoBinaryPath est défini. markdown-it reste utilisé pour les opérations basées sur les tokens.",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "En Markdown, un seul caractère de saut de ligne ne provoque pas de saut de ligne dans le HTML généré. En GitHub Flavored Markdown, ce n'est pas le cas. Activez cette option pour insérer des sauts de ligne dans le HTML rendu pour chaque saut de ligne unique dans la source Markdown.",
    +  "markdown-preview-enhanced.scrollSync.description": "Synchronisation automatique du défilement. Actuellement partiellement prise en charge.",
    +  "markdown-preview-enhanced.liveUpdate.description": "Effectue à nouveau le rendu de l'aperçu à mesure que le contenu de la source change, sans qu'il soit nécessaire d'enregistrer la mémoire tampon de la source. Si cette option est désactivée, l'aperçu n'est recalculé que lorsque la mémoire tampon est enregistrée sur le disque.",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "Délai d'anti-rebond en millisecondes pour les mises à jour en direct. Des valeurs plus élevées réduisent l'utilisation du processeur mais peuvent sembler moins réactives. Des valeurs plus faibles offrent un retour plus immédiat mais peuvent affecter les performances.",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview** : un seul aperçu est affiché pour tous les éditeurs.\n- **Multiple Previews** : plusieurs aperçus sont affichés. Chaque éditeur a son propre aperçu.\n- **Previews Only** : aucun éditeur n'est affiché. Seuls les aperçus sont affichés. Vous pouvez utiliser l'éditeur intégré à l'aperçu pour modifier le Markdown.\n\nUn redémarrage est requis après modification.",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "Afficher automatiquement l'aperçu du Markdown en cours de modification.",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "Liste des schémas d'URI (par exemple `vscode-notebook-cell`) à exclure de la fonctionnalité `automaticallyShowPreviewOfMarkdownBeingEdited`. Les fichiers correspondant à ces schémas ne déclencheront pas l'aperçu automatique.",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "Liste de motifs de noms de fichiers (par exemple `*.note.md`) à exclure de la fonctionnalité `automaticallyShowPreviewOfMarkdownBeingEdited`. Les fichiers dont le nom correspond à l'un de ces motifs ne déclencheront pas l'aperçu automatique. Prend en charge `*` comme caractère générique. La correspondance porte sur le nom de base du fichier (et non le chemin complet) et ne tient pas compte de la casse.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "Utiliser le paramètre `markdown-preview-enhanced.previewTheme`.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "Suivre le jeu de couleurs du système. Si la valeur est true, le thème de l'aperçu Markdown bascule automatiquement entre clair et sombre lorsque votre système bascule entre clair et sombre. Par exemple, si le thème d'aperçu actuel est `github-light.css`, lorsque votre système est en sombre, le thème de l'aperçu bascule automatiquement vers `github-dark.css`. Si la valeur est false, le thème de l'aperçu ne change pas automatiquement.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "Utiliser le même thème que l'éditeur (clair ou sombre). Si la valeur est true, le thème de l'aperçu Markdown bascule automatiquement entre clair et sombre lorsque vous basculez entre le thème clair et sombre de VS Code. Par exemple, si le thème d'aperçu actuel est `github-light.css`, lorsque vous passez au thème sombre de VS Code, le thème de l'aperçu bascule automatiquement vers `github-dark.css`. Si la valeur est false, le thème de l'aperçu ne change pas automatiquement.",
    +  "markdown-preview-enhanced.enableTypographer.description": "Activer smartypants et d'autres transformations typographiques.",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "Choisissez ici la méthode de rendu des expressions mathématiques. Vous pouvez aussi désactiver le rendu mathématique en choisissant 'None'.",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "Utiliser des délimiteurs personnalisés pour les expressions mathématiques en ligne.",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "Utiliser des délimiteurs personnalisés pour les blocs d'expressions mathématiques.",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "Choisissez la méthode de rendu des expressions mathématiques pour l'exportation Markdown GFM (Enregistrer en tant que Markdown).",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "Source du script MathJax. Laissez-la vide pour utiliser le CDN par défaut (MathJax v4).",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "Activer la prise en charge de la syntaxe des liens Wiki. Vous trouverez plus d'informations sur https://help.github.com/articles/adding-links-to-wikis/",
    +  "markdown-preview-enhanced.enableLinkify.description": "Activer ou désactiver la conversion du texte de type URL en liens dans l'aperçu Markdown.",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "Si cette case est cochée, nous utilisons des liens Wiki avec barre verticale de style GitHub, c'est-à-dire [[linkText|wikiLink]]. Sinon, nous utilisons [[wikiLink|linkText]], le style original de Wikipédia.",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "Activer le plug-in emoji et font-awesome. Cela ne fonctionne qu'avec l'analyseur markdown-it, pas avec l'analyseur pandoc.",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "Activer la syntaxe de tableau étendue pour prendre en charge la fusion de cellules de tableau.",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "Activer la syntaxe CriticMarkup. Ne fonctionne qu'avec l'analyseur markdown-it. Consultez http://criticmarkup.com/users-guide.php pour plus d'informations.",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "Activer la syntaxe d'étiquettes #tag de style Obsidian. Affiche `#tag-name` (et les éléments imbriqués `#parent/child`) sous forme d'ancres cliquables en forme de pilule. Cliquez sur une étiquette pour ouvrir la « Recherche dans les fichiers » de VS Code pré-remplie avec l'étiquette.",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "Taille maximale (en octets) d'un fichier Markdown que crossnote chargera dans l'index de notes en mémoire. Les fichiers dépassant la limite sont ignorés lors de l'actualisation de l'espace de travail : ils n'apparaîtront pas dans l'autocomplétion, les rétroliens ou le panneau d'étiquettes, mais vous pouvez toujours les ouvrir via un clic sur un lien wiki. Cela évite les cas pathologiques où un vidage de journaux/données portant l'extension `.md` conserverait l'intégralité de son contenu (plus un arbre de tokens analysé) en mémoire. Définissez la valeur sur `0` pour désactiver la limite.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "L'extension de fichier du lien dans un lien wiki si le lien n'a pas d'extension.",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "Comment les liens wiki ne comportant qu'un nom de fichier (par exemple `[[Note]]`) sont résolus en chemin de fichier.\n\n- `relative` — résolution relative au répertoire de la note actuelle (par défaut).\n- `shortest` — recherche dans toutes les notes par nom de fichier, en privilégiant le chemin unique le plus court (avec départage dans le même répertoire). Style Obsidian.\n- `absolute` — résolution depuis la racine du carnet/de l'espace de travail.\n\nLes liens commençant par `/` sont toujours résolus depuis la racine du carnet, quel que soit ce paramètre.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "Résolution relative au répertoire de la note actuelle.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "Recherche dans toutes les notes par nom de fichier, en privilégiant le chemin unique le plus court.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "Résolution depuis la racine du carnet/de l'espace de travail.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "La casse du nom de fichier dans un lien wiki. Si la valeur est `none`, le nom de fichier n'est pas modifié. Sinon, le nom de fichier est transformé selon la casse spécifiée. Vous pouvez consulter https://www.npmjs.com/package/case-anything pour plus de détails.",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Option de rendu du front matter",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Thème Mermaid, vous pouvez en choisir un parmi [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"]",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "Thème des blocs de code. Si `auto.css` est choisi, le thème de bloc de code qui correspond le mieux au thème d'aperçu actuel sera sélectionné.",
    +  "markdown-preview-enhanced.previewTheme.description": "Thème de l'aperçu",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "Aucun",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "Thème de présentation RevealJS",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "Protocoles acceptés pour les liens.",
    +  "markdown-preview-enhanced.imageFolderPath.description": "Lorsque vous utilisez l'Assistant d'images pour copier des images, par défaut les images sont copiées dans le chemin du dossier d'images racine '/assets'",
    +  "markdown-preview-enhanced.imageUploader.description": "Vous pouvez choisir différents services pour téléverser les images",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "Qiniu AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "Qiniu SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "Qiniu Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "Qiniu Domain",
    +  "markdown-preview-enhanced.printBackground.description": "Indique s'il faut imprimer l'arrière-plan lors de l'exportation de fichiers. Si la valeur est `false`, le thème d'aperçu `github-light` est utilisé. Vous pouvez aussi définir `print_background` dans le front-matter de fichiers individuels.",
    +  "markdown-preview-enhanced.chromePath.description": "Chemin de l'exécutable Chrome, utilisé pour l'exportation Puppeteer. Le laisser vide signifie que le chemin sera trouvé automatiquement.",
    +  "markdown-preview-enhanced.imageMagickPath.description": "Chemin de la ligne de commande ImageMagick. Doit être `magick` ou `convert`. Le laisser vide signifie que le chemin sera trouvé automatiquement.",
    +  "markdown-preview-enhanced.pandocPath.description": "Chemin de l'exécutable Pandoc",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "Chemin du binaire natif markdown_yo. Lorsqu'il est défini et que markdownParser vaut 'markdown_yo', crossnote utilisera ce binaire (via stdin/stdout) au lieu du module WASM intégré. Le binaire natif est plus rapide pour les fichiers de moins de ~300 Ko ; WASM est plus rapide pour les très grands fichiers. Prend en charge la substitution des variables $HOME et ~. Laissez-le vide pour utiliser WASM (par défaut).",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "La variante de Markdown Pandoc souhaitée",
    +  "markdown-preview-enhanced.pandocArguments.description": "Arguments passés à la commande pandoc, par exemple [\"--smart\", \"--filter=/bin/exe\"]. Veuillez utiliser les noms d'arguments longs.",
    +  "markdown-preview-enhanced.latexEngine.description": "Moteur latex par défaut pour l'exportation Pandoc et les blocs de code latex.",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "Active l'exécution des blocs de code et l'importation de fichiers JavaScript.\n⚠️ Veuillez utiliser cette fonctionnalité avec prudence car elle peut compromettre votre sécurité ! Votre machine peut être piratée si quelqu'un vous fait ouvrir un Markdown contenant du code malveillant alors que l'exécution de scripts est activée.",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": "Active la transformation des liens audio/vidéo en balises audio/vidéo intégrées HTML5.",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": "Active l'intégration vidéo/audio avec la syntaxe ![]() (par défaut).",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "Active l'intégration vidéo/audio avec la syntaxe []().",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "Si true, intègre les médias dont l'URL utilise le schéma http://. Si false, les ignore et ne les intègre pas.",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "Attributs HTML à passer aux balises audio.",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "Attributs HTML à passer aux balises vidéo.",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "Puppeteer attend un certain délai en millisecondes avant l'exportation du document.",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "Arguments passés à puppeteer.launch({args: $puppeteerArgs})",
    +  "markdown-preview-enhanced.plantumlServer.description": "Effectuer le rendu à l'aide d'un serveur PlantUML au lieu du binaire. Laissez-le vide pour utiliser le binaire plantuml.jar intégré (`java` est requis dans le chemin système). Ex. : \"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "Masquer les boutons de l'extension d'aperçu Markdown par défaut de VS Code. Le redémarrage de l'éditeur est nécessaire pour que ce paramètre prenne effet.",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "Hôte du CDN jsDelivr. Exemples de valeurs : `cdn.jsdelivr.net`, `fastly.jsdelivr.net`, `gcore.jsdelivr.net`, `testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "Chemin absolu vers le fichier plantuml.jar (`java` est requis dans le chemin système). Vous pouvez le télécharger depuis https://plantuml.com/download.",
    +  "markdown-preview-enhanced.krokiServer.description": "L'URL du serveur Kroki à utiliser.",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "L'URL du serveur WebSequenceDiagrams à utiliser pour le rendu des blocs de code wsd.",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "Clé d'API pour WebSequenceDiagrams. Requise pour des tailles de diagramme plus grandes.",
    +  "markdown-preview-enhanced.d2Path.description": "Chemin de l'exécutable D2. Par défaut `d2` (c'est-à-dire trouvé dans le PATH). Non pris en charge dans l'extension web.",
    +  "markdown-preview-enhanced.d2Layout.description": "Moteur de disposition D2 par défaut pour le rendu des diagrammes d2.",
    +  "markdown-preview-enhanced.d2Theme.description": "Thème D2 par défaut pour le rendu des diagrammes d2.",
    +  "markdown-preview-enhanced.d2Sketch.description": "Effectuer le rendu des diagrammes D2 dans un style esquissé (dessiné à la main).",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Extensions de fichier Markdown. Utilisé pour déterminer s'il faut afficher le bouton d'aperçu dans le menu contextuel des fichiers Markdown.",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "Toujours afficher les rétroliens dans l'aperçu.",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "Activer cette option masquera les éléments d'interface inutiles dans l'aperçu, sauf lorsque votre souris se trouve dessus.",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "Lorsque cette option est activée, le menu contextuel de l'aperçu hérite des couleurs et de la police du thème de VS Code au lieu du style par défaut.",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "Cliquez sur une image dans l'aperçu pour la voir dans une superposition lightbox en plein écran. Appuyez sur Échap ou cliquez sur l'arrière-plan pour fermer."
     }
    
  • package.nls.ja.json+99 1 modified
    @@ -27,5 +27,103 @@
       "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:パーサーを拡張(ワークスペース)",
       "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:プレビュー HTML ヘッドをカスタマイズ(グローバル)",
       "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:プレビュー HTML ヘッドをカスタマイズ(ワークスペース)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "MPE:アップロードされた画像を表示"
    +  "markdown-preview-enhanced.showUploadedImages.title": "MPE:アップロードされた画像を表示",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "変更後に再起動が必要です。グローバル設定ディレクトリのパス。空のままにすると、Windows では `$HOME/.crossnote`、それ以外では `$XDG_CONFIG_HOME/.crossnote` または `$HOME/.local/state/crossnote` が設定パスとして使用されます。",
    +  "markdown-preview-enhanced.markdownParser.description": "使用する Markdown パーサー/レンダラー。'markdown-it'(既定)は組み込みレンダラーです。'pandoc' は Pandoc を使用します(Pandoc のインストールが必要。VS Code Web では利用不可)。'markdown_yo' は高性能な WASM レンダラー(markdownYoBinaryPath を設定した場合はネイティブバイナリ。実験的)を使用します。",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "組み込みの markdown-it レンダラー(既定)。",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "Pandoc を使用してレンダリングします。Pandoc のインストールが必要です。VS Code Web では利用できません。",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "高性能レンダラー(実験的)。既定では WASM を使用し、markdownYoBinaryPath を設定した場合はネイティブバイナリを使用します。トークンベースの処理には引き続き markdown-it が使用されます。",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "Markdown では、単一の改行文字は生成される HTML では改行になりません。GitHub Flavored Markdown ではそうではありません。このオプションを有効にすると、Markdown ソースの単一の改行が、レンダリングされた HTML で改行として挿入されます。",
    +  "markdown-preview-enhanced.scrollSync.description": "自動スクロール同期。現在、部分的にサポートされています。",
    +  "markdown-preview-enhanced.liveUpdate.description": "ソースバッファーを保存しなくても、ソースの内容の変更に合わせてプレビューを再レンダリングします。無効にすると、バッファーがディスクに保存されたときにのみプレビューが再レンダリングされます。",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "ライブ更新のデバウンス時間(ミリ秒)。値を大きくすると CPU 使用率は下がりますが、応答が遅く感じられる場合があります。値を小さくすると反応は速くなりますが、パフォーマンスに影響する場合があります。",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview**: すべてのエディターに対して 1 つのプレビューのみが表示されます。\n- **Multiple Previews**: 複数のプレビューが表示されます。各エディターが独自のプレビューを持ちます。\n- **Previews Only**: エディターは表示されず、プレビューのみが表示されます。プレビュー内のエディターで Markdown を編集できます。\n\n変更後に再起動が必要です。",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "編集中の Markdown のプレビューを自動的に表示します。",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "`automaticallyShowPreviewOfMarkdownBeingEdited` 機能から除外する URI スキームのリスト(例: `vscode-notebook-cell`)。これらのスキームに一致するファイルは自動プレビューをトリガーしません。",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "`automaticallyShowPreviewOfMarkdownBeingEdited` 機能から除外するファイル名パターンのリスト(例: `*.note.md`)。いずれかのパターンに一致する名前のファイルは自動プレビューをトリガーしません。ワイルドカードとして `*` を使用できます。照合はファイルのベース名(フルパスではなく)に対して行われ、大文字と小文字を区別しません。",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "`markdown-preview-enhanced.previewTheme` 設定を使用します。",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "システムのカラースキームに従います。true に設定すると、システムがライトとダークを切り替えたときに Markdown プレビューのテーマも自動的に切り替わります。たとえば、現在のプレビューテーマを `github-light.css` に設定している場合、システムがダークになるとプレビューテーマは自動的に `github-dark.css` に切り替わります。false に設定すると、プレビューのテーマは自動的に変更されません。",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "エディターと同じテーマ(ライトまたはダーク)を使用します。true に設定すると、VS Code のライトとダークのテーマを切り替えたときに Markdown プレビューのテーマも自動的に切り替わります。たとえば、現在のプレビューテーマを `github-light.css` に設定している場合、VS Code のダークテーマに切り替えるとプレビューテーマは自動的に `github-dark.css` に切り替わります。false に設定すると、プレビューのテーマは自動的に変更されません。",
    +  "markdown-preview-enhanced.enableTypographer.description": "smartypants やその他の便利な変換を有効にします。",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "ここで数式のレンダリング方法を選択します。不要な場合は 'None' を選択して数式レンダリングを無効にすることもできます。",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "カスタマイズしたインライン数式の区切り文字を使用します。",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "カスタマイズしたブロック数式の区切り文字を使用します。",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "GFM Markdown エクスポート(Markdown として保存)の数式レンダリング方法を選択します。",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "MathJax スクリプトのソース。空のままにすると既定の CDN(MathJax v4)が使用されます。",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "Wiki リンク構文のサポートを有効にします。詳細は https://help.github.com/articles/adding-links-to-wikis/ を参照してください。",
    +  "markdown-preview-enhanced.enableLinkify.description": "Markdown プレビューで URL のようなテキストをリンクに変換する機能を有効または無効にします。",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "チェックすると、GitHub スタイルのパイプ区切り Wiki リンク、すなわち [[linkText|wikiLink]] を使用します。それ以外の場合は、元の Wikipedia スタイルである [[wikiLink|linkText]] を使用します。",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "emoji と font-awesome プラグインを有効にします。これは markdown-it パーサーでのみ機能し、pandoc パーサーでは機能しません。",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "テーブルのセル結合をサポートする拡張テーブル構文を有効にします。",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "CriticMarkup 構文を有効にします。markdown-it パーサーでのみ機能します。詳細は http://criticmarkup.com/users-guide.php を参照してください。",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "Obsidian スタイルの #tag 構文を有効にします。`#tag-name`(およびネストした `#parent/child`)をクリック可能なピル型のアンカーとしてレンダリングします。タグをクリックすると、そのタグが事前入力された VS Code の「ファイル内検索」が開きます。",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "crossnote がメモリ内のノートインデックスに読み込む Markdown ファイルの最大サイズ(バイト)。上限を超えるファイルはワークスペースの更新時にスキップされ、オートコンプリート、バックリンク、タグパネルには表示されませんが、Wiki リンクのクリックで開くことはできます。`.md` 拡張子の付いたログ/データダンプがその全内容(および解析済みのトークンツリー)をメモリに常駐させてしまう病的なケースを防ぎます。`0` に設定すると上限が無効になります。",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "Wiki リンクに拡張子がない場合に、そのリンクに使用するファイル拡張子。",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "ファイル名のみの Wiki リンク(例: `[[Note]]`)をファイルパスに解決する方法。\n\n- `relative` — 現在のノートのディレクトリを基準に解決します(既定)。\n- `shortest` — すべてのノートをファイル名で検索し、最短の一意なパスを優先します(同一ディレクトリを優先)。Obsidian スタイル。\n- `absolute` — ノートブック/ワークスペースのルートから解決します。\n\n`/` で始まるリンクは、この設定に関係なく常にノートブックのルートから解決されます。",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "現在のノートのディレクトリを基準に解決します。",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "すべてのノートをファイル名で検索し、最短の一意なパスを優先します。",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "ノートブック/ワークスペースのルートから解決します。",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "Wiki リンク内のファイル名の大文字小文字。値が `none` の場合、ファイル名は変更されません。それ以外の場合、ファイル名は指定された形式に変換されます。詳細は https://www.npmjs.com/package/case-anything を参照してください。",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Front matter のレンダリングオプション",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Mermaid テーマ。[\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"] から 1 つ選択できます",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "コードブロックのテーマ。`auto.css` を選択すると、現在のプレビューテーマに最も合うコードブロックのテーマが選択されます。",
    +  "markdown-preview-enhanced.previewTheme.description": "プレビューテーマ",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "なし",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "RevealJS プレゼンテーションテーマ",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "リンクで許可するプロトコル。",
    +  "markdown-preview-enhanced.imageFolderPath.description": "画像ヘルパーで画像をコピーする際、既定では画像はルート画像フォルダーパス '/assets' にコピーされます",
    +  "markdown-preview-enhanced.imageUploader.description": "さまざまな画像アップローダーを選択して画像をアップロードできます",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "Qiniu AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "Qiniu SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "Qiniu Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "Qiniu Domain",
    +  "markdown-preview-enhanced.printBackground.description": "ファイルのエクスポート時に背景を印刷するかどうか。`false` に設定すると、`github-light` プレビューテーマが使用されます。個々のファイルの front-matter で `print_background` を設定することもできます。",
    +  "markdown-preview-enhanced.chromePath.description": "Puppeteer エクスポートに使用される Chrome 実行ファイルのパス。空のままにすると、パスが自動的に検出されます。",
    +  "markdown-preview-enhanced.imageMagickPath.description": "ImageMagick のコマンドラインパス。`magick` または `convert` のいずれかである必要があります。空のままにすると、パスが自動的に検出されます。",
    +  "markdown-preview-enhanced.pandocPath.description": "Pandoc 実行ファイルのパス",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "markdown_yo ネイティブバイナリのパス。これを設定し、markdownParser が 'markdown_yo' の場合、crossnote は組み込みの WASM モジュールの代わりにこのバイナリを(stdin/stdout 経由で)使用します。約 300 KB 未満のファイルではネイティブバイナリの方が高速で、非常に大きなファイルでは WASM の方が高速です。$HOME と ~ の変数置換をサポートします。空のままにすると WASM(既定)が使用されます。",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "使用したい Pandoc Markdown フレーバー",
    +  "markdown-preview-enhanced.pandocArguments.description": "pandoc コマンドに渡す引数。例: [\"--smart\", \"--filter=/bin/exe\"]。長い引数名を使用してください。",
    +  "markdown-preview-enhanced.latexEngine.description": "Pandoc エクスポートと latex コードチャンクの既定の latex エンジン。",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "コードチャンクの実行と JavaScript ファイルのインポートを有効にします。\n⚠️ この機能はセキュリティ上のリスクを伴う可能性があるため、注意して使用してください。スクリプト実行が有効な状態で悪意のあるコードを含む Markdown を開かされると、マシンが乗っ取られる可能性があります。",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": "オーディオ/ビデオのリンクを HTML5 の埋め込み audio/video タグに変換する機能を有効にします。",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": "![]() 構文でのビデオ/オーディオ埋め込みを有効にします(既定)。",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "[]() 構文でのビデオ/オーディオ埋め込みを有効にします。",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "true の場合、URL に http:// スキームを含むメディアを埋め込みます。false の場合、それらを無視して埋め込みません。",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "audio タグに渡す HTML 属性。",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "video タグに渡す HTML 属性。",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "Puppeteer がドキュメントのエクスポート前に待機する時間(ミリ秒)。",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "puppeteer.launch({args: $puppeteerArgs}) に渡す引数",
    +  "markdown-preview-enhanced.plantumlServer.description": "バイナリの代わりに PlantUML サーバーを使用してレンダリングします。空のままにすると、組み込みの plantuml.jar バイナリが使用されます(システムパスに `java` が必要)。例: \"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "VS Code の既定の Markdown プレビュー拡張機能のボタンを非表示にします。この設定を反映するにはエディターの再起動が必要です。",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "jsDelivr CDN ホスト。値の例: `cdn.jsdelivr.net`、`fastly.jsdelivr.net`、`gcore.jsdelivr.net`、`testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "plantuml.jar ファイルへの絶対パス(システムパスに `java` が必要)。https://plantuml.com/download からダウンロードできます。",
    +  "markdown-preview-enhanced.krokiServer.description": "使用する Kroki サーバーの URL。",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "wsd コードブロックのレンダリングに使用する WebSequenceDiagrams サーバーの URL。",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "WebSequenceDiagrams の API キー。より大きな図のサイズに必要です。",
    +  "markdown-preview-enhanced.d2Path.description": "D2 実行ファイルへのパス。既定は `d2`(PATH 上にあること)。Web 拡張機能ではサポートされません。",
    +  "markdown-preview-enhanced.d2Layout.description": "d2 図のレンダリングに使用する既定の D2 レイアウトエンジン。",
    +  "markdown-preview-enhanced.d2Theme.description": "d2 図のレンダリングに使用する既定の D2 テーマ。",
    +  "markdown-preview-enhanced.d2Sketch.description": "D2 図を手描き(スケッチ)スタイルでレンダリングします。",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Markdown ファイルの拡張子。Markdown ファイルのコンテキストメニューにプレビューボタンを表示するかどうかの判定に使用されます。",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "プレビューに常にバックリンクを表示します。",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "このオプションを有効にすると、マウスを乗せていない限り、プレビュー内の不要な UI 要素が非表示になります。",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "有効にすると、プレビュー内のコンテキストメニューが既定のスタイルではなく VS Code のテーマカラーとフォントを継承します。",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "プレビュー内の画像をクリックすると、全画面のライトボックスオーバーレイで表示できます。Escape を押すか背景をクリックすると閉じます。"
     }
    
  • package.nls.json+99 1 modified
    @@ -27,5 +27,103 @@
       "markdown-preview-enhanced.extendParserInWorkspace.title": "Markdown Preview Enhanced: Extend Parser (Workspace)",
       "markdown-preview-enhanced.customizePreviewHtmlHead.title": "Markdown Preview Enhanced: Customize Preview Html Head (Global)",
       "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "Markdown Preview Enhanced: Customize Preview Html Head (Workspace)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "Markdown Preview Enhanced: Show Uploaded Images"
    +  "markdown-preview-enhanced.showUploadedImages.title": "Markdown Preview Enhanced: Show Uploaded Images",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "Restart is required after changes. The global configuration directory path. Leave it empty to use `$HOME/.crossnote` for Windows or `$XDG_CONFIG_HOME/.crossnote` or `$HOME/.local/state/crossnote` as the config path.",
    +  "markdown-preview-enhanced.markdownParser.description": "Markdown parser/renderer to use. 'markdown-it' (default) is the built-in renderer. 'pandoc' uses Pandoc (requires Pandoc installed; not available in VS Code web). 'markdown_yo' uses a high-performance WASM renderer (or native binary when markdownYoBinaryPath is set; experimental).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "Built-in markdown-it renderer (default).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "Render via Pandoc. Requires Pandoc to be installed. Not available in VS Code web.",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "High-performance renderer (experimental). Uses WASM by default, or a native binary when markdownYoBinaryPath is set. markdown-it is still used for token-based operations.",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "In Markdown, a single newline character doesn't cause a line break in the generated HTML. In GitHub Flavored Markdown, that is not true. Enable this config option to insert line breaks in rendered HTML for single newlines in Markdown source.",
    +  "markdown-preview-enhanced.scrollSync.description": "Automatic scroll sync. This is now partially supported.",
    +  "markdown-preview-enhanced.liveUpdate.description": "Re-render the preview as the contents of the source changes, without requiring the source buffer to be saved. If disabled, the preview is re-rendered only when the buffer is saved to disk.",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "Debounce time in milliseconds for live updates. Higher values reduce CPU usage but may feel less responsive. Lower values provide more immediate feedback but may impact performance.",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview**: Only one preview will be shown for all editors.\n- **Multiple Previews**: Multiple previews will be shown. Each editor has its own preview.\n- **Previews Only**: No editor will be shown. Only previews will be shown. You can use the in-preview editor to edit the markdown.\n\nRestart is required after changes.",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "Automatically show preview of markdown being edited.",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "A list of URI schemes (e.g., `vscode-notebook-cell`) to exclude from the `automaticallyShowPreviewOfMarkdownBeingEdited` feature. Files matching these schemes won't trigger the automatic preview.",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "A list of file name patterns (e.g., `*.note.md`) to exclude from the `automaticallyShowPreviewOfMarkdownBeingEdited` feature. Files whose names match any of these patterns won't trigger the automatic preview. Supports `*` as a wildcard. Matching is performed against the file's basename (not full path) and is case-insensitive.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "Use the `markdown-preview-enhanced.previewTheme` setting.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "Follow system color scheme. If set to true, then the theme of markdown preview will automatically switch between light and dark when your system switch between light and dark. For example, if you set the current preview theme to `github-light.css`, then when your system is dark, the preview theme will be switched to `github-dark.css` automatically. If set to false, then the theme of markdown preview will not be changed automatically.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "Use the same theme as the editor (light or dark). If set to true, then the theme of markdown preview will automatically switch between light and dark when you switch between vscode light and dark theme. For example, if you set the current preview theme to `github-light.css`, then when you switch to vscode dark theme, the preview theme will be switched to `github-dark.css` automatically. If set to false, then the theme of markdown preview will not be changed automatically.",
    +  "markdown-preview-enhanced.enableTypographer.description": "Enable smartypants and other sweet transforms.",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "Choose the Math expression rendering method here. You can also disable math rendering if you want by choosing 'None'.",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "Use customized Math expression inline delimiters.",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "Use customized Math expression block delimiters.",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "Choose the Math expression rendering method option for GFM markdown export (Save as Markdown).",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "MathJax script source. Leave it empty to use the default CDN (MathJax v4).",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "Enable Wiki Link syntax support. More information can be found at https://help.github.com/articles/adding-links-to-wikis/",
    +  "markdown-preview-enhanced.enableLinkify.description": "Enable or disable conversion of URL-like text to links in the markdown preview.",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "If checked, we use GitHub style piped wiki links, i.e. [[linkText|wikiLink]]. Otherwise, we use [[wikiLink|linkText]] as the original Wikipedia style.",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "Enable emoji & font-awesome plugin. This only works for markdown-it parser, but not pandoc parser.",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "Enable extended table syntax to support merging table cells.",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "Enable CriticMarkup syntax. Only works with markdown-it parser. Please check http://criticmarkup.com/users-guide.php for more information.",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "Enable Obsidian-style #tag syntax. Renders `#tag-name` (and nested `#parent/child`) as clickable pill-shaped anchors. Click a tag to open VS Code's \"Search in Files\" pre-filled with the tag.",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "Maximum size (in bytes) of a Markdown file that crossnote will load into the in-memory note index. Files larger than the cap are skipped during workspace refresh — they won't appear in autocomplete, backlinks, or the tag panel, but you can still open them via wikilink click. Prevents pathological cases where a checked-in log/data dump with a `.md` extension would otherwise pin its full content (plus a parsed token tree) in memory. Set to `0` to disable the cap.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "The file extension for the link in wikilink if the link does not have an extension.",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "How bare-filename wiki links (e.g. `[[Note]]`) are resolved to a file path.\n\n- `relative` — resolve relative to the current note's directory (default).\n- `shortest` — search all notes by filename, preferring the shortest unique path (with same-directory tiebreaking). Obsidian-style.\n- `absolute` — resolve from the notebook/workspace root.\n\nLinks starting with `/` always resolve from the notebook root regardless of this setting.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "Resolve relative to the current note's directory.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "Search all notes by filename, preferring the shortest unique path.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "Resolve from the notebook/workspace root.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "The case for the file name in wikilink. If the value is `none`, then the file name will not be changed. Otherwise, the file name will be transformed to the specified case. You can read https://www.npmjs.com/package/case-anything for more details.",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Front matter rendering option",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Mermaid theme, you can choose one from [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"]",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "Code block theme. If `auto.css` is chosen, then the code block theme that best matches the current preview theme will be picked.",
    +  "markdown-preview-enhanced.previewTheme.description": "Preview Theme",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "None",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "RevealJS Presentation Theme",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "Accepted protocols for links.",
    +  "markdown-preview-enhanced.imageFolderPath.description": "When using Image Helper to copy images, by default images will be copied to root image folder path '/assets'",
    +  "markdown-preview-enhanced.imageUploader.description": "You can choose different image uploader to upload image",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "Qiniu AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "Qiniu SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "Qiniu Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "Qiniu Domain",
    +  "markdown-preview-enhanced.printBackground.description": "Whether to print background for file export or not. If set to `false`, then `github-light` preview theme will be used. You can also set `print_background` in front-matter for individual files.",
    +  "markdown-preview-enhanced.chromePath.description": "Chrome executable path, which is used for Puppeteer export. Leaving it empty means the path will be found automatically.",
    +  "markdown-preview-enhanced.imageMagickPath.description": "ImageMagick command line path. Should be either `magick` or `convert`. Leaving it empty means the path will be found automatically.",
    +  "markdown-preview-enhanced.pandocPath.description": "Pandoc executable path",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "Path to the markdown_yo native binary. When set and markdownParser is 'markdown_yo', crossnote will use this binary (via stdin/stdout) instead of the bundled WASM module. The native binary is faster for files under ~300 KB; WASM is faster for very large files. Supports $HOME and ~ variable substitution. Leave empty to use WASM (default).",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "The pandoc markdown flavor you want",
    +  "markdown-preview-enhanced.pandocArguments.description": "Args passed to pandoc command e.g. [\"--smart\", \"--filter=/bin/exe\"] Please use long argument names.",
    +  "markdown-preview-enhanced.latexEngine.description": "Default latex engine for Pandoc export and latex code chunk.",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "Enables executing code chunks and importing javascript files.\n⚠️ Please use this feature with caution because it may put your security at risk! Your machine can get hacked if someone makes you open a markdown with malicious code while script execution is enabled.",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": " Enables transform audio video link to to html5 embed audio video tags.",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": " Enables video/audio embed with ![]() syntax (default).",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "Enables video/audio embed with []() syntax.",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "When true embed media with http:// schema in URLs. When false ignore and don't embed them.",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "HTML attributes to pass to audio tags.",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "HTML attributes to pass to video tags.",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "Puppeteer waits for a certain timeout in milliseconds before the document export.",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "Args passed to puppeteer.launch({args: $puppeteerArgs})",
    +  "markdown-preview-enhanced.plantumlServer.description": "Render using PlantUML server instead of binary. Leave it empty to use the builtin plantuml.jar binary (`java` is required in system path). Eg: \"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "Hide the default VSCode markdown preview extension buttons. Restarting the editor is required to make this config take effect.",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "jsDelivr CDN host. Example values: `cdn.jsdelivr.net`, `fastly.jsdelivr.net`, `gcore.jsdelivr.net`, `testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "Absolute path to the plantuml.jar file (`java` is required in system path). You can download it from https://plantuml.com/download.",
    +  "markdown-preview-enhanced.krokiServer.description": "The URL of the Kroki server to use.  ",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "The URL of the WebSequenceDiagrams server to use for rendering wsd code blocks.",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "API key for WebSequenceDiagrams. Required for wider diagram sizes.",
    +  "markdown-preview-enhanced.d2Path.description": "Path to the D2 executable. Defaults to `d2` (i.e. found on PATH). Not supported in the web extension.",
    +  "markdown-preview-enhanced.d2Layout.description": "Default D2 layout engine for rendering d2 diagrams.",
    +  "markdown-preview-enhanced.d2Theme.description": "Default D2 theme for rendering d2 diagrams.",
    +  "markdown-preview-enhanced.d2Sketch.description": "Render D2 diagrams in sketch (hand-drawn) style.",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Markdown file extensions. This is used to determine whether to show the preview button in the markdown file context menu.",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "Always show backlinks in preview.",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "Enable this option will hide unnecessary UI elements in preview unless your mouse is over it.",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "When enabled, the context menu in preview inherits VS Code's theme colors and font instead of the default styling.",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "Click an image in the preview to view it in a full-screen lightbox overlay. Press Escape or click the backdrop to close."
     }
    
  • package.nls.ko.json+99 1 modified
    @@ -27,5 +27,103 @@
       "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:파서 확장(작업 영역)",
       "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:미리보기 HTML 헤드 사용자 정의(전역)",
       "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:미리보기 HTML 헤드 사용자 정의(작업 영역)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "MPE:업로드된 이미지 보기"
    +  "markdown-preview-enhanced.showUploadedImages.title": "MPE:업로드된 이미지 보기",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "변경 후 재시작이 필요합니다. 전역 설정 디렉터리 경로입니다. 비워 두면 Windows에서는 `$HOME/.crossnote`, 그 외에는 `$XDG_CONFIG_HOME/.crossnote` 또는 `$HOME/.local/state/crossnote`가 설정 경로로 사용됩니다.",
    +  "markdown-preview-enhanced.markdownParser.description": "사용할 Markdown 파서/렌더러입니다. 'markdown-it'(기본값)은 내장 렌더러입니다. 'pandoc'은 Pandoc을 사용합니다(Pandoc 설치 필요. VS Code 웹에서는 사용할 수 없음). 'markdown_yo'는 고성능 WASM 렌더러(markdownYoBinaryPath가 설정된 경우 네이티브 바이너리. 실험적)를 사용합니다.",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "내장 markdown-it 렌더러(기본값).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "Pandoc을 통해 렌더링합니다. Pandoc 설치가 필요합니다. VS Code 웹에서는 사용할 수 없습니다.",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "고성능 렌더러(실험적). 기본적으로 WASM을 사용하며, markdownYoBinaryPath가 설정된 경우 네이티브 바이너리를 사용합니다. 토큰 기반 작업에는 여전히 markdown-it이 사용됩니다.",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "Markdown에서는 단일 줄바꿈 문자가 생성된 HTML에서 줄바꿈을 일으키지 않습니다. GitHub Flavored Markdown에서는 그렇지 않습니다. 이 옵션을 활성화하면 Markdown 소스의 단일 줄바꿈이 렌더링된 HTML에서 줄바꿈으로 삽입됩니다.",
    +  "markdown-preview-enhanced.scrollSync.description": "자동 스크롤 동기화. 현재 부분적으로 지원됩니다.",
    +  "markdown-preview-enhanced.liveUpdate.description": "소스 버퍼를 저장하지 않아도 소스 내용이 변경될 때 미리 보기를 다시 렌더링합니다. 비활성화하면 버퍼가 디스크에 저장될 때만 미리 보기가 다시 렌더링됩니다.",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "라이브 업데이트의 디바운스 시간(밀리초). 값이 클수록 CPU 사용량이 줄지만 응답이 느리게 느껴질 수 있습니다. 값이 작을수록 반응이 즉각적이지만 성능에 영향을 줄 수 있습니다.",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview**: 모든 편집기에 대해 하나의 미리 보기만 표시됩니다.\n- **Multiple Previews**: 여러 미리 보기가 표시됩니다. 각 편집기가 자체 미리 보기를 가집니다.\n- **Previews Only**: 편집기가 표시되지 않고 미리 보기만 표시됩니다. 미리 보기 내 편집기를 사용하여 Markdown을 편집할 수 있습니다.\n\n변경 후 재시작이 필요합니다.",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "편집 중인 Markdown의 미리 보기를 자동으로 표시합니다.",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "`automaticallyShowPreviewOfMarkdownBeingEdited` 기능에서 제외할 URI 스킴 목록입니다(예: `vscode-notebook-cell`). 이러한 스킴과 일치하는 파일은 자동 미리 보기를 트리거하지 않습니다.",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "`automaticallyShowPreviewOfMarkdownBeingEdited` 기능에서 제외할 파일 이름 패턴 목록입니다(예: `*.note.md`). 이름이 이러한 패턴 중 하나와 일치하는 파일은 자동 미리 보기를 트리거하지 않습니다. 와일드카드로 `*`를 지원합니다. 일치 여부는 파일의 기본 이름(전체 경로가 아님)에 대해 수행되며 대소문자를 구분하지 않습니다.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "`markdown-preview-enhanced.previewTheme` 설정을 사용합니다.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "시스템 색 구성표를 따릅니다. true로 설정하면 시스템이 밝은 테마와 어두운 테마를 전환할 때 Markdown 미리 보기 테마도 자동으로 전환됩니다. 예를 들어 현재 미리 보기 테마를 `github-light.css`로 설정한 경우, 시스템이 어두워지면 미리 보기 테마가 자동으로 `github-dark.css`로 전환됩니다. false로 설정하면 미리 보기 테마가 자동으로 변경되지 않습니다.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "편집기와 동일한 테마(밝게 또는 어둡게)를 사용합니다. true로 설정하면 VS Code의 밝은 테마와 어두운 테마를 전환할 때 Markdown 미리 보기 테마도 자동으로 전환됩니다. 예를 들어 현재 미리 보기 테마를 `github-light.css`로 설정한 경우, VS Code 어두운 테마로 전환하면 미리 보기 테마가 자동으로 `github-dark.css`로 전환됩니다. false로 설정하면 미리 보기 테마가 자동으로 변경되지 않습니다.",
    +  "markdown-preview-enhanced.enableTypographer.description": "smartypants 및 기타 유용한 변환을 활성화합니다.",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "여기서 수식 렌더링 방법을 선택합니다. 필요하지 않으면 'None'을 선택하여 수식 렌더링을 비활성화할 수도 있습니다.",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "사용자 지정 인라인 수식 구분 기호를 사용합니다.",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "사용자 지정 블록 수식 구분 기호를 사용합니다.",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "GFM Markdown 내보내기(Markdown으로 저장)의 수식 렌더링 방법을 선택합니다.",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "MathJax 스크립트 소스입니다. 비워 두면 기본 CDN(MathJax v4)이 사용됩니다.",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "Wiki 링크 구문 지원을 활성화합니다. 자세한 내용은 https://help.github.com/articles/adding-links-to-wikis/ 를 참조하세요.",
    +  "markdown-preview-enhanced.enableLinkify.description": "Markdown 미리 보기에서 URL과 유사한 텍스트를 링크로 변환하는 기능을 활성화하거나 비활성화합니다.",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "선택하면 GitHub 스타일의 파이프 구분 Wiki 링크, 즉 [[linkText|wikiLink]]를 사용합니다. 그렇지 않으면 원래 Wikipedia 스타일인 [[wikiLink|linkText]]를 사용합니다.",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "emoji 및 font-awesome 플러그인을 활성화합니다. 이는 markdown-it 파서에서만 작동하며 pandoc 파서에서는 작동하지 않습니다.",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "표 셀 병합을 지원하는 확장 표 구문을 활성화합니다.",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "CriticMarkup 구문을 활성화합니다. markdown-it 파서에서만 작동합니다. 자세한 내용은 http://criticmarkup.com/users-guide.php 를 참조하세요.",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "Obsidian 스타일의 #tag 구문을 활성화합니다. `#tag-name`(및 중첩된 `#parent/child`)을 클릭 가능한 알약 모양 앵커로 렌더링합니다. 태그를 클릭하면 해당 태그가 미리 입력된 VS Code의 '파일에서 검색'이 열립니다.",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "crossnote가 메모리 내 노트 인덱스에 로드하는 Markdown 파일의 최대 크기(바이트)입니다. 상한을 초과하는 파일은 작업 영역 새로 고침 중에 건너뛰며, 자동 완성, 백링크 또는 태그 패널에 표시되지 않지만 Wiki 링크 클릭으로는 열 수 있습니다. `.md` 확장자를 가진 로그/데이터 덤프가 전체 내용(및 구문 분석된 토큰 트리)을 메모리에 상주시키는 비정상적인 상황을 방지합니다. `0`으로 설정하면 상한이 비활성화됩니다.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "Wiki 링크에 확장자가 없는 경우 해당 링크에 사용할 파일 확장자입니다.",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "파일 이름만 있는 Wiki 링크(예: `[[Note]]`)를 파일 경로로 확인하는 방법입니다.\n\n- `relative` — 현재 노트의 디렉터리를 기준으로 확인합니다(기본값).\n- `shortest` — 모든 노트를 파일 이름으로 검색하여 가장 짧은 고유 경로를 우선합니다(동일 디렉터리 우선). Obsidian 스타일.\n- `absolute` — 노트북/작업 영역 루트에서 확인합니다.\n\n`/`로 시작하는 링크는 이 설정과 관계없이 항상 노트북 루트에서 확인됩니다.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "현재 노트의 디렉터리를 기준으로 확인합니다.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "모든 노트를 파일 이름으로 검색하여 가장 짧은 고유 경로를 우선합니다.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "노트북/작업 영역 루트에서 확인합니다.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "Wiki 링크 내 파일 이름의 대소문자입니다. 값이 `none`이면 파일 이름이 변경되지 않습니다. 그렇지 않으면 파일 이름이 지정된 형식으로 변환됩니다. 자세한 내용은 https://www.npmjs.com/package/case-anything 를 참조하세요.",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Front matter 렌더링 옵션",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Mermaid 테마. [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"] 중 하나를 선택할 수 있습니다",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "코드 블록 테마입니다. `auto.css`를 선택하면 현재 미리 보기 테마에 가장 잘 맞는 코드 블록 테마가 선택됩니다.",
    +  "markdown-preview-enhanced.previewTheme.description": "미리 보기 테마",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "없음",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "RevealJS 프레젠테이션 테마",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "링크에 허용되는 프로토콜입니다.",
    +  "markdown-preview-enhanced.imageFolderPath.description": "이미지 도우미로 이미지를 복사할 때 기본적으로 이미지는 루트 이미지 폴더 경로 '/assets'에 복사됩니다",
    +  "markdown-preview-enhanced.imageUploader.description": "다양한 이미지 업로더를 선택하여 이미지를 업로드할 수 있습니다",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "Qiniu AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "Qiniu SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "Qiniu Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "Qiniu Domain",
    +  "markdown-preview-enhanced.printBackground.description": "파일 내보내기 시 배경을 인쇄할지 여부입니다. `false`로 설정하면 `github-light` 미리 보기 테마가 사용됩니다. 개별 파일의 front-matter에서 `print_background`를 설정할 수도 있습니다.",
    +  "markdown-preview-enhanced.chromePath.description": "Puppeteer 내보내기에 사용되는 Chrome 실행 파일 경로입니다. 비워 두면 경로가 자동으로 검색됩니다.",
    +  "markdown-preview-enhanced.imageMagickPath.description": "ImageMagick 명령줄 경로입니다. `magick` 또는 `convert` 중 하나여야 합니다. 비워 두면 경로가 자동으로 검색됩니다.",
    +  "markdown-preview-enhanced.pandocPath.description": "Pandoc 실행 파일 경로",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "markdown_yo 네이티브 바이너리 경로입니다. 이 값을 설정하고 markdownParser가 'markdown_yo'이면 crossnote는 내장 WASM 모듈 대신 이 바이너리를(stdin/stdout을 통해) 사용합니다. 약 300KB 미만의 파일에서는 네이티브 바이너리가 더 빠르고, 매우 큰 파일에서는 WASM이 더 빠릅니다. $HOME 및 ~ 변수 치환을 지원합니다. 비워 두면 WASM(기본값)이 사용됩니다.",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "사용하려는 Pandoc Markdown 방식",
    +  "markdown-preview-enhanced.pandocArguments.description": "pandoc 명령에 전달되는 인수입니다. 예: [\"--smart\", \"--filter=/bin/exe\"]. 긴 인수 이름을 사용하세요.",
    +  "markdown-preview-enhanced.latexEngine.description": "Pandoc 내보내기 및 latex 코드 청크의 기본 latex 엔진입니다.",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "코드 청크 실행 및 JavaScript 파일 가져오기를 활성화합니다.\n⚠️ 이 기능은 보안 위험을 초래할 수 있으므로 주의해서 사용하세요! 스크립트 실행이 활성화된 상태에서 악성 코드가 포함된 Markdown을 열도록 유도되면 컴퓨터가 해킹될 수 있습니다.",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": "오디오/비디오 링크를 HTML5 임베드 audio/video 태그로 변환하는 기능을 활성화합니다.",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": "![]() 구문을 사용한 비디오/오디오 임베드를 활성화합니다(기본값).",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "[]() 구문을 사용한 비디오/오디오 임베드를 활성화합니다.",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "true이면 URL에 http:// 스킴이 있는 미디어를 임베드합니다. false이면 무시하고 임베드하지 않습니다.",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "audio 태그에 전달할 HTML 속성입니다.",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "video 태그에 전달할 HTML 속성입니다.",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "Puppeteer가 문서 내보내기 전에 대기하는 시간(밀리초)입니다.",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "puppeteer.launch({args: $puppeteerArgs})에 전달되는 인수입니다.",
    +  "markdown-preview-enhanced.plantumlServer.description": "바이너리 대신 PlantUML 서버를 사용하여 렌더링합니다. 비워 두면 내장 plantuml.jar 바이너리가 사용됩니다(시스템 경로에 `java` 필요). 예: \"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "VS Code 기본 Markdown 미리 보기 확장의 버튼을 숨깁니다. 이 설정을 적용하려면 편집기를 다시 시작해야 합니다.",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "jsDelivr CDN 호스트입니다. 예시 값: `cdn.jsdelivr.net`, `fastly.jsdelivr.net`, `gcore.jsdelivr.net`, `testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "plantuml.jar 파일의 절대 경로입니다(시스템 경로에 `java` 필요). https://plantuml.com/download 에서 다운로드할 수 있습니다.",
    +  "markdown-preview-enhanced.krokiServer.description": "사용할 Kroki 서버의 URL입니다.",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "wsd 코드 블록 렌더링에 사용할 WebSequenceDiagrams 서버의 URL입니다.",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "WebSequenceDiagrams의 API 키입니다. 더 큰 다이어그램 크기에 필요합니다.",
    +  "markdown-preview-enhanced.d2Path.description": "D2 실행 파일 경로입니다. 기본값은 `d2`(즉, PATH에서 찾음)입니다. 웹 확장에서는 지원되지 않습니다.",
    +  "markdown-preview-enhanced.d2Layout.description": "d2 다이어그램 렌더링에 사용할 기본 D2 레이아웃 엔진입니다.",
    +  "markdown-preview-enhanced.d2Theme.description": "d2 다이어그램 렌더링에 사용할 기본 D2 테마입니다.",
    +  "markdown-preview-enhanced.d2Sketch.description": "D2 다이어그램을 손으로 그린(스케치) 스타일로 렌더링합니다.",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Markdown 파일 확장자입니다. Markdown 파일 컨텍스트 메뉴에 미리 보기 버튼을 표시할지 여부를 결정하는 데 사용됩니다.",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "미리 보기에 항상 백링크를 표시합니다.",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "이 옵션을 활성화하면 마우스를 올려놓지 않는 한 미리 보기의 불필요한 UI 요소가 숨겨집니다.",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "활성화하면 미리 보기의 컨텍스트 메뉴가 기본 스타일 대신 VS Code의 테마 색상과 글꼴을 상속합니다.",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "미리 보기의 이미지를 클릭하면 전체 화면 라이트박스 오버레이에서 볼 수 있습니다. Escape를 누르거나 배경을 클릭하면 닫힙니다."
     }
    
  • package.nls.nl.json+99 1 modified
    @@ -27,5 +27,103 @@
       "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:Parser uitbreiden (Werkruimte)",
       "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:HTML-head aanpassen (Globaal)",
       "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:HTML-head aanpassen (Werkruimte)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Geüploade afbeeldingen tonen"
    +  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Geüploade afbeeldingen tonen",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "Opnieuw opstarten is vereist na wijzigingen. Pad naar de globale configuratiemap. Laat dit leeg om `$HOME/.crossnote` op Windows te gebruiken, of `$XDG_CONFIG_HOME/.crossnote` of `$HOME/.local/state/crossnote` als configuratiepad.",
    +  "markdown-preview-enhanced.markdownParser.description": "De te gebruiken Markdown-parser/renderer. 'markdown-it' (standaard) is de ingebouwde renderer. 'pandoc' gebruikt Pandoc (vereist dat Pandoc is geïnstalleerd; niet beschikbaar in VS Code web). 'markdown_yo' gebruikt een hoogwaardige WASM-renderer (of een native binary wanneer markdownYoBinaryPath is ingesteld; experimenteel).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "Ingebouwde markdown-it-renderer (standaard).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "Rendert via Pandoc. Vereist dat Pandoc is geïnstalleerd. Niet beschikbaar in VS Code web.",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "Hoogwaardige renderer (experimenteel). Gebruikt standaard WASM, of een native binary wanneer markdownYoBinaryPath is ingesteld. markdown-it wordt nog steeds gebruikt voor token-gebaseerde bewerkingen.",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "In Markdown veroorzaakt een enkel regeleindeteken geen regelafbreking in de gegenereerde HTML. In GitHub Flavored Markdown is dat niet zo. Schakel deze optie in om regelafbrekingen in de gerenderde HTML in te voegen voor enkele regeleindes in de Markdown-bron.",
    +  "markdown-preview-enhanced.scrollSync.description": "Automatische scroll-synchronisatie. Dit wordt nu gedeeltelijk ondersteund.",
    +  "markdown-preview-enhanced.liveUpdate.description": "Rendert het voorbeeld opnieuw terwijl de inhoud van de bron verandert, zonder dat de bronbuffer hoeft te worden opgeslagen. Indien uitgeschakeld, wordt het voorbeeld alleen opnieuw gerenderd wanneer de buffer naar schijf wordt opgeslagen.",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "Debounce-tijd in milliseconden voor live-updates. Hogere waarden verminderen het CPU-gebruik maar kunnen minder responsief aanvoelen. Lagere waarden geven directere feedback maar kunnen de prestaties beïnvloeden.",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview**: er wordt slechts één voorbeeld getoond voor alle editors.\n- **Multiple Previews**: er worden meerdere voorbeelden getoond. Elke editor heeft zijn eigen voorbeeld.\n- **Previews Only**: er wordt geen editor getoond. Alleen voorbeelden worden getoond. U kunt de editor in het voorbeeld gebruiken om de Markdown te bewerken.\n\nOpnieuw opstarten is vereist na wijzigingen.",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "Toon automatisch een voorbeeld van de Markdown die wordt bewerkt.",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "Een lijst met URI-schema's (bijv. `vscode-notebook-cell`) die moeten worden uitgesloten van de functie `automaticallyShowPreviewOfMarkdownBeingEdited`. Bestanden die overeenkomen met deze schema's activeren het automatische voorbeeld niet.",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "Een lijst met bestandsnaampatronen (bijv. `*.note.md`) die moeten worden uitgesloten van de functie `automaticallyShowPreviewOfMarkdownBeingEdited`. Bestanden waarvan de naam overeenkomt met een van deze patronen activeren het automatische voorbeeld niet. Ondersteunt `*` als jokerteken. De vergelijking wordt uitgevoerd op de basisnaam van het bestand (niet het volledige pad) en is niet hoofdlettergevoelig.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "De instelling `markdown-preview-enhanced.previewTheme` gebruiken.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "Het kleurenschema van het systeem volgen. Indien ingesteld op true, schakelt het thema van het Markdown-voorbeeld automatisch tussen licht en donker wanneer uw systeem tussen licht en donker schakelt. Als het huidige voorbeeldthema bijvoorbeeld is ingesteld op `github-light.css`, wordt het voorbeeldthema automatisch overgeschakeld naar `github-dark.css` wanneer uw systeem donker is. Indien ingesteld op false, wordt het thema van het voorbeeld niet automatisch gewijzigd.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "Hetzelfde thema als de editor gebruiken (licht of donker). Indien ingesteld op true, schakelt het thema van het Markdown-voorbeeld automatisch tussen licht en donker wanneer u schakelt tussen het lichte en donkere thema van VS Code. Als het huidige voorbeeldthema bijvoorbeeld is ingesteld op `github-light.css`, wordt het voorbeeldthema automatisch overgeschakeld naar `github-dark.css` wanneer u overschakelt naar het donkere thema van VS Code. Indien ingesteld op false, wordt het thema van het voorbeeld niet automatisch gewijzigd.",
    +  "markdown-preview-enhanced.enableTypographer.description": "Schakel smartypants en andere handige transformaties in.",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "Kies hier de renderingmethode voor wiskundige expressies. U kunt de wiskunderendering ook uitschakelen door 'None' te kiezen.",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "Aangepaste scheidingstekens voor inline wiskundige expressies gebruiken.",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "Aangepaste scheidingstekens voor blok-wiskundige expressies gebruiken.",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "Kies de renderingmethode voor wiskundige expressies voor GFM Markdown-export (Opslaan als Markdown).",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "MathJax-scriptbron. Laat dit leeg om de standaard-CDN (MathJax v4) te gebruiken.",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "Ondersteuning voor Wiki-linksyntaxis inschakelen. Meer informatie vindt u op https://help.github.com/articles/adding-links-to-wikis/",
    +  "markdown-preview-enhanced.enableLinkify.description": "De conversie van URL-achtige tekst naar links in het Markdown-voorbeeld in- of uitschakelen.",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "Indien aangevinkt, gebruiken we Wiki-links met pipe-teken in GitHub-stijl, d.w.z. [[linkText|wikiLink]]. Anders gebruiken we [[wikiLink|linkText]], de oorspronkelijke Wikipedia-stijl.",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "De emoji- en font-awesome-plug-in inschakelen. Dit werkt alleen voor de markdown-it-parser, niet voor de pandoc-parser.",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "Uitgebreide tabelsyntaxis inschakelen ter ondersteuning van het samenvoegen van tabelcellen.",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "CriticMarkup-syntaxis inschakelen. Werkt alleen met de markdown-it-parser. Zie http://criticmarkup.com/users-guide.php voor meer informatie.",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "#tag-syntaxis in Obsidian-stijl inschakelen. Rendert `#tag-name` (en geneste `#parent/child`) als klikbare pilvormige ankers. Klik op een tag om 'Zoeken in bestanden' van VS Code te openen, vooraf ingevuld met de tag.",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "Maximale grootte (in bytes) van een Markdown-bestand dat crossnote in de in-memory notitie-index laadt. Bestanden die groter zijn dan de limiet worden overgeslagen tijdens het vernieuwen van de werkruimte — ze verschijnen niet in automatisch aanvullen, backlinks of het tagpaneel, maar u kunt ze nog steeds openen via een wikilink-klik. Voorkomt pathologische gevallen waarin een log-/datadump met de extensie `.md` anders zijn volledige inhoud (plus een geparseerde tokenstructuur) in het geheugen zou houden. Stel in op `0` om de limiet uit te schakelen.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "De bestandsextensie voor de link in een wikilink als de link geen extensie heeft.",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "Hoe wikilinks met alleen een bestandsnaam (bijv. `[[Note]]`) worden omgezet naar een bestandspad.\n\n- `relative` — omzetten ten opzichte van de map van de huidige notitie (standaard).\n- `shortest` — zoekt alle notities op bestandsnaam, met voorkeur voor het kortste unieke pad (met voorrang voor dezelfde map). Obsidian-stijl.\n- `absolute` — omzetten vanaf de hoofdmap van het notitieboek/de werkruimte.\n\nLinks die met `/` beginnen, worden altijd omgezet vanaf de hoofdmap van het notitieboek, ongeacht deze instelling.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "Omzetten ten opzichte van de map van de huidige notitie.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "Zoekt alle notities op bestandsnaam, met voorkeur voor het kortste unieke pad.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "Omzetten vanaf de hoofdmap van het notitieboek/de werkruimte.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "De hoofdletter-/kleinletternotatie voor de bestandsnaam in een wikilink. Als de waarde `none` is, wordt de bestandsnaam niet gewijzigd. Anders wordt de bestandsnaam omgezet naar de opgegeven notatie. Zie https://www.npmjs.com/package/case-anything voor meer details.",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Renderingoptie voor front matter",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Mermaid-thema, u kunt er een kiezen uit [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"]",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "Thema voor codeblokken. Als `auto.css` wordt gekozen, wordt het codeblokthema gekozen dat het beste past bij het huidige voorbeeldthema.",
    +  "markdown-preview-enhanced.previewTheme.description": "Voorbeeldthema",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "Geen",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "RevealJS-presentatiethema",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "Geaccepteerde protocollen voor links.",
    +  "markdown-preview-enhanced.imageFolderPath.description": "Wanneer u de Afbeeldingshelper gebruikt om afbeeldingen te kopiëren, worden afbeeldingen standaard gekopieerd naar het hoofdpad van de afbeeldingenmap '/assets'",
    +  "markdown-preview-enhanced.imageUploader.description": "U kunt verschillende afbeeldinguploaders kiezen om afbeeldingen te uploaden",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "Qiniu AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "Qiniu SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "Qiniu Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "Qiniu Domain",
    +  "markdown-preview-enhanced.printBackground.description": "Of de achtergrond al dan niet wordt afgedrukt bij het exporteren van bestanden. Indien ingesteld op `false`, wordt het voorbeeldthema `github-light` gebruikt. U kunt `print_background` ook instellen in de front-matter voor afzonderlijke bestanden.",
    +  "markdown-preview-enhanced.chromePath.description": "Pad naar het uitvoerbare bestand van Chrome, dat wordt gebruikt voor Puppeteer-export. Leeg laten betekent dat het pad automatisch wordt gevonden.",
    +  "markdown-preview-enhanced.imageMagickPath.description": "Opdrachtregelpad van ImageMagick. Moet `magick` of `convert` zijn. Leeg laten betekent dat het pad automatisch wordt gevonden.",
    +  "markdown-preview-enhanced.pandocPath.description": "Pad naar het uitvoerbare bestand van Pandoc",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "Pad naar de native binary van markdown_yo. Wanneer dit is ingesteld en markdownParser 'markdown_yo' is, gebruikt crossnote deze binary (via stdin/stdout) in plaats van de ingebouwde WASM-module. De native binary is sneller voor bestanden kleiner dan ~300 KB; WASM is sneller voor zeer grote bestanden. Ondersteunt substitutie van de variabelen $HOME en ~. Laat leeg om WASM te gebruiken (standaard).",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "De gewenste Pandoc Markdown-variant",
    +  "markdown-preview-enhanced.pandocArguments.description": "Argumenten die aan de pandoc-opdracht worden doorgegeven, bijv. [\"--smart\", \"--filter=/bin/exe\"]. Gebruik lange argumentnamen.",
    +  "markdown-preview-enhanced.latexEngine.description": "Standaard latex-engine voor Pandoc-export en latex-codeblokken.",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "Schakelt het uitvoeren van codeblokken en het importeren van JavaScript-bestanden in.\n⚠️ Gebruik deze functie met voorzichtigheid, want het kan uw beveiliging in gevaar brengen! Uw computer kan worden gehackt als iemand u een Markdown met schadelijke code laat openen terwijl scriptuitvoering is ingeschakeld.",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": "Schakelt het omzetten van audio-/videolinks naar ingesloten HTML5 audio-/video-tags in.",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": "Schakelt het insluiten van video/audio met de ![]()-syntaxis in (standaard).",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "Schakelt het insluiten van video/audio met de []()-syntaxis in.",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "Indien true, sluit media met het http://-schema in URL's in. Indien false, worden ze genegeerd en niet ingesloten.",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "HTML-attributen die aan audio-tags worden doorgegeven.",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "HTML-attributen die aan video-tags worden doorgegeven.",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "Puppeteer wacht een bepaalde time-out in milliseconden vóór het exporteren van het document.",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "Argumenten die aan puppeteer.launch({args: $puppeteerArgs}) worden doorgegeven",
    +  "markdown-preview-enhanced.plantumlServer.description": "Renderen met een PlantUML-server in plaats van de binary. Laat dit leeg om de ingebouwde plantuml.jar-binary te gebruiken (`java` is vereist in het systeempad). Bijv.: \"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "De knoppen van de standaard Markdown-voorbeeldextensie van VS Code verbergen. De editor moet opnieuw worden opgestart om deze instelling van kracht te laten worden.",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "jsDelivr CDN-host. Voorbeeldwaarden: `cdn.jsdelivr.net`, `fastly.jsdelivr.net`, `gcore.jsdelivr.net`, `testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "Absoluut pad naar het plantuml.jar-bestand (`java` is vereist in het systeempad). U kunt het downloaden van https://plantuml.com/download.",
    +  "markdown-preview-enhanced.krokiServer.description": "De URL van de te gebruiken Kroki-server.",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "De URL van de te gebruiken WebSequenceDiagrams-server voor het renderen van wsd-codeblokken.",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "API-sleutel voor WebSequenceDiagrams. Vereist voor grotere diagramformaten.",
    +  "markdown-preview-enhanced.d2Path.description": "Pad naar het uitvoerbare bestand van D2. Standaard `d2` (d.w.z. gevonden in PATH). Niet ondersteund in de web-extensie.",
    +  "markdown-preview-enhanced.d2Layout.description": "Standaard D2-lay-out-engine voor het renderen van d2-diagrammen.",
    +  "markdown-preview-enhanced.d2Theme.description": "Standaard D2-thema voor het renderen van d2-diagrammen.",
    +  "markdown-preview-enhanced.d2Sketch.description": "D2-diagrammen renderen in schetsstijl (met de hand getekend).",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Markdown-bestandsextensies. Dit wordt gebruikt om te bepalen of de voorbeeldknop wordt getoond in het contextmenu van het Markdown-bestand.",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "Altijd backlinks tonen in het voorbeeld.",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "Door deze optie in te schakelen worden onnodige UI-elementen in het voorbeeld verborgen, tenzij uw muis erboven zweeft.",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "Indien ingeschakeld neemt het contextmenu in het voorbeeld de themakleuren en het lettertype van VS Code over in plaats van de standaardstijl.",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "Klik op een afbeelding in het voorbeeld om deze te bekijken in een schermvullende lightbox-overlay. Druk op Escape of klik op de achtergrond om te sluiten."
     }
    
  • package.nls.pt-br.json+99 1 modified
    @@ -27,5 +27,103 @@
       "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:Estender analisador (Área de trabalho)",
       "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:Personalizar cabeçalho HTML (Global)",
       "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:Personalizar cabeçalho HTML (Área de trabalho)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Mostrar imagens enviadas"
    +  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Mostrar imagens enviadas",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "É necessário reiniciar após as alterações. Caminho do diretório de configuração global. Deixe-o vazio para usar `$HOME/.crossnote` no Windows, ou `$XDG_CONFIG_HOME/.crossnote` ou `$HOME/.local/state/crossnote` como caminho de configuração.",
    +  "markdown-preview-enhanced.markdownParser.description": "Analisador/renderizador de Markdown a ser usado. 'markdown-it' (padrão) é o renderizador integrado. 'pandoc' usa o Pandoc (requer o Pandoc instalado; não disponível no VS Code web). 'markdown_yo' usa um renderizador WASM de alto desempenho (ou um binário nativo quando markdownYoBinaryPath é definido; experimental).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "Renderizador markdown-it integrado (padrão).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "Renderiza via Pandoc. Requer que o Pandoc esteja instalado. Não disponível no VS Code web.",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "Renderizador de alto desempenho (experimental). Usa WASM por padrão, ou um binário nativo quando markdownYoBinaryPath é definido. O markdown-it ainda é usado para operações baseadas em tokens.",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "No Markdown, um único caractere de quebra de linha não causa uma quebra de linha no HTML gerado. No GitHub Flavored Markdown, isso não acontece. Ative esta opção para inserir quebras de linha no HTML renderizado para cada quebra de linha única na fonte Markdown.",
    +  "markdown-preview-enhanced.scrollSync.description": "Sincronização automática de rolagem. Atualmente com suporte parcial.",
    +  "markdown-preview-enhanced.liveUpdate.description": "Renderiza novamente a visualização à medida que o conteúdo da fonte muda, sem precisar salvar o buffer de origem. Se desativado, a visualização só é renderizada novamente quando o buffer é salvo em disco.",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "Tempo de debounce em milissegundos para atualizações ao vivo. Valores mais altos reduzem o uso da CPU, mas podem parecer menos responsivos. Valores mais baixos oferecem um retorno mais imediato, mas podem afetar o desempenho.",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview**: apenas uma visualização será mostrada para todos os editores.\n- **Multiple Previews**: várias visualizações serão mostradas. Cada editor tem sua própria visualização.\n- **Previews Only**: nenhum editor será mostrado. Apenas as visualizações serão mostradas. Você pode usar o editor dentro da visualização para editar o Markdown.\n\nÉ necessário reiniciar após as alterações.",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "Mostrar automaticamente a visualização do Markdown que está sendo editado.",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "Lista de esquemas de URI (por exemplo, `vscode-notebook-cell`) a serem excluídos do recurso `automaticallyShowPreviewOfMarkdownBeingEdited`. Os arquivos que correspondem a esses esquemas não acionarão a visualização automática.",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "Lista de padrões de nome de arquivo (por exemplo, `*.note.md`) a serem excluídos do recurso `automaticallyShowPreviewOfMarkdownBeingEdited`. Os arquivos cujos nomes correspondem a qualquer um desses padrões não acionarão a visualização automática. Suporta `*` como curinga. A correspondência é feita com base no nome base do arquivo (não no caminho completo) e não diferencia maiúsculas de minúsculas.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "Usar a configuração `markdown-preview-enhanced.previewTheme`.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "Seguir o esquema de cores do sistema. Se definido como true, o tema da visualização do Markdown alternará automaticamente entre claro e escuro quando o sistema alternar entre claro e escuro. Por exemplo, se o tema de visualização atual for `github-light.css`, quando o sistema estiver no escuro, o tema da visualização será alternado automaticamente para `github-dark.css`. Se definido como false, o tema da visualização não será alterado automaticamente.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "Usar o mesmo tema do editor (claro ou escuro). Se definido como true, o tema da visualização do Markdown alternará automaticamente entre claro e escuro quando você alternar entre o tema claro e escuro do VS Code. Por exemplo, se o tema de visualização atual for `github-light.css`, ao mudar para o tema escuro do VS Code, o tema da visualização será alternado automaticamente para `github-dark.css`. Se definido como false, o tema da visualização não será alterado automaticamente.",
    +  "markdown-preview-enhanced.enableTypographer.description": "Ativar o smartypants e outras transformações tipográficas.",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "Escolha aqui o método de renderização de expressões matemáticas. Você também pode desativar a renderização de matemática escolhendo 'None'.",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "Usar delimitadores personalizados para expressões matemáticas em linha.",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "Usar delimitadores personalizados para blocos de expressões matemáticas.",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "Escolha o método de renderização de expressões matemáticas para a exportação de Markdown GFM (Salvar como Markdown).",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "Origem do script do MathJax. Deixe-a vazia para usar o CDN padrão (MathJax v4).",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "Ativar o suporte à sintaxe de links Wiki. Mais informações podem ser encontradas em https://help.github.com/articles/adding-links-to-wikis/",
    +  "markdown-preview-enhanced.enableLinkify.description": "Ativar ou desativar a conversão de texto semelhante a URL em links na visualização do Markdown.",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "Se marcado, usamos links Wiki com barra vertical no estilo do GitHub, ou seja, [[linkText|wikiLink]]. Caso contrário, usamos [[wikiLink|linkText]], o estilo original da Wikipédia.",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "Ativar o plug-in de emoji e font-awesome. Isso só funciona com o analisador markdown-it, não com o analisador pandoc.",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "Ativar a sintaxe de tabela estendida para dar suporte à mesclagem de células de tabela.",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "Ativar a sintaxe CriticMarkup. Só funciona com o analisador markdown-it. Consulte http://criticmarkup.com/users-guide.php para mais informações.",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "Ativar a sintaxe de tags #tag no estilo do Obsidian. Renderiza `#tag-name` (e os aninhados `#parent/child`) como âncoras clicáveis em formato de pílula. Clique em uma tag para abrir a \"Pesquisar em Arquivos\" do VS Code já preenchida com a tag.",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "Tamanho máximo (em bytes) de um arquivo Markdown que o crossnote carregará no índice de notas em memória. Arquivos maiores que o limite são ignorados durante a atualização do espaço de trabalho — eles não aparecerão no preenchimento automático, nos backlinks ou no painel de tags, mas você ainda pode abri-los clicando em um link wiki. Evita casos patológicos em que um despejo de logs/dados com extensão `.md` manteria todo o seu conteúdo (mais uma árvore de tokens analisada) na memória. Defina como `0` para desativar o limite.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "A extensão de arquivo para o link em um link wiki, caso o link não tenha extensão.",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "Como os links wiki apenas com nome de arquivo (por exemplo, `[[Note]]`) são resolvidos para um caminho de arquivo.\n\n- `relative` — resolve em relação ao diretório da nota atual (padrão).\n- `shortest` — pesquisa em todas as notas por nome de arquivo, preferindo o caminho único mais curto (com desempate no mesmo diretório). Estilo Obsidian.\n- `absolute` — resolve a partir da raiz do caderno/espaço de trabalho.\n\nLinks que começam com `/` são sempre resolvidos a partir da raiz do caderno, independentemente desta configuração.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "Resolve em relação ao diretório da nota atual.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "Pesquisa em todas as notas por nome de arquivo, preferindo o caminho único mais curto.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "Resolve a partir da raiz do caderno/espaço de trabalho.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "A capitalização do nome do arquivo em um link wiki. Se o valor for `none`, o nome do arquivo não será alterado. Caso contrário, o nome do arquivo será transformado para a capitalização especificada. Você pode ler https://www.npmjs.com/package/case-anything para mais detalhes.",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Opção de renderização do front matter",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Tema do Mermaid, você pode escolher um entre [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"]",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "Tema dos blocos de código. Se `auto.css` for escolhido, o tema de bloco de código que melhor corresponder ao tema de visualização atual será selecionado.",
    +  "markdown-preview-enhanced.previewTheme.description": "Tema da visualização",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "Nenhum",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "Tema de apresentação RevealJS",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "Protocolos aceitos para links.",
    +  "markdown-preview-enhanced.imageFolderPath.description": "Ao usar o Assistente de Imagens para copiar imagens, por padrão as imagens serão copiadas para o caminho da pasta de imagens raiz '/assets'",
    +  "markdown-preview-enhanced.imageUploader.description": "Você pode escolher diferentes serviços para enviar imagens",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "Qiniu AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "Qiniu SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "Qiniu Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "Qiniu Domain",
    +  "markdown-preview-enhanced.printBackground.description": "Se deve ou não imprimir o plano de fundo na exportação de arquivos. Se definido como `false`, o tema de visualização `github-light` será usado. Você também pode definir `print_background` no front-matter de arquivos individuais.",
    +  "markdown-preview-enhanced.chromePath.description": "Caminho do executável do Chrome, usado para a exportação com o Puppeteer. Deixá-lo vazio significa que o caminho será encontrado automaticamente.",
    +  "markdown-preview-enhanced.imageMagickPath.description": "Caminho da linha de comando do ImageMagick. Deve ser `magick` ou `convert`. Deixá-lo vazio significa que o caminho será encontrado automaticamente.",
    +  "markdown-preview-enhanced.pandocPath.description": "Caminho do executável do Pandoc",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "Caminho para o binário nativo do markdown_yo. Quando definido e markdownParser for 'markdown_yo', o crossnote usará este binário (via stdin/stdout) em vez do módulo WASM integrado. O binário nativo é mais rápido para arquivos com menos de ~300 KB; o WASM é mais rápido para arquivos muito grandes. Suporta a substituição das variáveis $HOME e ~. Deixe vazio para usar o WASM (padrão).",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "A variante de Markdown do Pandoc que você deseja",
    +  "markdown-preview-enhanced.pandocArguments.description": "Argumentos passados para o comando pandoc, por exemplo [\"--smart\", \"--filter=/bin/exe\"]. Use nomes de argumentos longos.",
    +  "markdown-preview-enhanced.latexEngine.description": "Mecanismo latex padrão para exportação com Pandoc e blocos de código latex.",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "Ativa a execução de blocos de código e a importação de arquivos JavaScript.\n⚠️ Use este recurso com cautela, pois ele pode colocar sua segurança em risco! Sua máquina pode ser invadida se alguém fizer você abrir um Markdown com código malicioso enquanto a execução de scripts estiver ativada.",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": "Ativa a transformação de links de áudio e vídeo em tags de áudio e vídeo incorporadas do HTML5.",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": "Ativa a incorporação de vídeo/áudio com a sintaxe ![]() (padrão).",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "Ativa a incorporação de vídeo/áudio com a sintaxe []().",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "Quando true, incorpora mídia com o esquema http:// nas URLs. Quando false, as ignora e não as incorpora.",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "Atributos HTML a serem passados para as tags de áudio.",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "Atributos HTML a serem passados para as tags de vídeo.",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "O Puppeteer aguarda um determinado tempo limite em milissegundos antes da exportação do documento.",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "Argumentos passados para puppeteer.launch({args: $puppeteerArgs})",
    +  "markdown-preview-enhanced.plantumlServer.description": "Renderizar usando um servidor PlantUML em vez do binário. Deixe-o vazio para usar o binário plantuml.jar integrado (`java` é necessário no caminho do sistema). Ex.: \"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "Ocultar os botões da extensão de visualização de Markdown padrão do VS Code. É necessário reiniciar o editor para que esta configuração tenha efeito.",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "Host do CDN jsDelivr. Valores de exemplo: `cdn.jsdelivr.net`, `fastly.jsdelivr.net`, `gcore.jsdelivr.net`, `testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "Caminho absoluto para o arquivo plantuml.jar (`java` é necessário no caminho do sistema). Você pode baixá-lo em https://plantuml.com/download.",
    +  "markdown-preview-enhanced.krokiServer.description": "A URL do servidor Kroki a ser usado.",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "A URL do servidor WebSequenceDiagrams a ser usado para renderizar blocos de código wsd.",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "Chave de API para o WebSequenceDiagrams. Necessária para tamanhos de diagrama maiores.",
    +  "markdown-preview-enhanced.d2Path.description": "Caminho para o executável do D2. O padrão é `d2` (ou seja, encontrado no PATH). Não suportado na extensão web.",
    +  "markdown-preview-enhanced.d2Layout.description": "Mecanismo de layout D2 padrão para renderizar diagramas d2.",
    +  "markdown-preview-enhanced.d2Theme.description": "Tema D2 padrão para renderizar diagramas d2.",
    +  "markdown-preview-enhanced.d2Sketch.description": "Renderizar diagramas D2 em estilo de esboço (desenhado à mão).",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Extensões de arquivo Markdown. Usado para determinar se o botão de visualização deve ser exibido no menu de contexto do arquivo Markdown.",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "Sempre mostrar backlinks na visualização.",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "Ativar esta opção ocultará elementos de interface desnecessários na visualização, a menos que o mouse esteja sobre eles.",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "Quando ativado, o menu de contexto na visualização herda as cores e a fonte do tema do VS Code em vez do estilo padrão.",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "Clique em uma imagem na visualização para vê-la em uma sobreposição de lightbox em tela cheia. Pressione Esc ou clique no fundo para fechar."
     }
    
  • package.nls.tr.json+99 1 modified
    @@ -27,5 +27,103 @@
       "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:Ayrıştırıcıyı genişlet (Çalışma alanı)",
       "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:Önizleme HTML başlığını özelleştir (Genel)",
       "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:Önizleme HTML başlığını özelleştir (Çalışma alanı)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Yüklenen görselleri göster"
    +  "markdown-preview-enhanced.showUploadedImages.title": "MPE:Yüklenen görselleri göster",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "Değişikliklerden sonra yeniden başlatma gerekir. Genel yapılandırma dizini yolu. Windows'ta `$HOME/.crossnote`, diğer durumlarda `$XDG_CONFIG_HOME/.crossnote` veya `$HOME/.local/state/crossnote` yolunu kullanmak için boş bırakın.",
    +  "markdown-preview-enhanced.markdownParser.description": "Kullanılacak Markdown ayrıştırıcısı/işleyicisi. 'markdown-it' (varsayılan) yerleşik işleyicidir. 'pandoc' Pandoc kullanır (Pandoc'un kurulu olması gerekir; VS Code web'de kullanılamaz). 'markdown_yo' yüksek performanslı bir WASM işleyicisi kullanır (markdownYoBinaryPath ayarlandığında yerel ikili dosya; deneysel).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "Yerleşik markdown-it işleyicisi (varsayılan).",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "Pandoc ile işler. Pandoc'un kurulu olması gerekir. VS Code web'de kullanılamaz.",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "Yüksek performanslı işleyici (deneysel). Varsayılan olarak WASM kullanır, markdownYoBinaryPath ayarlandığında yerel ikili dosya kullanır. Token tabanlı işlemler için markdown-it kullanılmaya devam eder.",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "Markdown'da tek bir yeni satır karakteri, oluşturulan HTML'de satır sonu oluşturmaz. GitHub Flavored Markdown'da durum böyle değildir. Markdown kaynağındaki tek satır sonları için oluşturulan HTML'de satır sonları eklemek üzere bu seçeneği etkinleştirin.",
    +  "markdown-preview-enhanced.scrollSync.description": "Otomatik kaydırma eşitlemesi. Bu artık kısmen desteklenmektedir.",
    +  "markdown-preview-enhanced.liveUpdate.description": "Kaynak arabelleğini kaydetmeye gerek kalmadan, kaynağın içeriği değiştikçe önizlemeyi yeniden işler. Devre dışı bırakılırsa, önizleme yalnızca arabellek diske kaydedildiğinde yeniden işlenir.",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "Canlı güncellemeler için milisaniye cinsinden debounce süresi. Daha yüksek değerler CPU kullanımını azaltır ancak daha az yanıt verir gibi hissettirebilir. Daha düşük değerler daha anında geri bildirim sağlar ancak performansı etkileyebilir.",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview**: Tüm düzenleyiciler için yalnızca bir önizleme gösterilir.\n- **Multiple Previews**: Birden çok önizleme gösterilir. Her düzenleyicinin kendi önizlemesi vardır.\n- **Previews Only**: Hiçbir düzenleyici gösterilmez. Yalnızca önizlemeler gösterilir. Markdown'ı düzenlemek için önizleme içindeki düzenleyiciyi kullanabilirsiniz.\n\nDeğişikliklerden sonra yeniden başlatma gerekir.",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "Düzenlenmekte olan Markdown'ın önizlemesini otomatik olarak göster.",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "`automaticallyShowPreviewOfMarkdownBeingEdited` özelliğinden hariç tutulacak URI şemalarının listesi (örneğin `vscode-notebook-cell`). Bu şemalarla eşleşen dosyalar otomatik önizlemeyi tetiklemez.",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "`automaticallyShowPreviewOfMarkdownBeingEdited` özelliğinden hariç tutulacak dosya adı kalıplarının listesi (örneğin `*.note.md`). Adı bu kalıplardan herhangi biriyle eşleşen dosyalar otomatik önizlemeyi tetiklemez. Joker karakter olarak `*` desteklenir. Eşleştirme, dosyanın temel adına (tam yola değil) göre yapılır ve büyük/küçük harfe duyarlı değildir.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "`markdown-preview-enhanced.previewTheme` ayarını kullan.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "Sistem renk düzenini izle. true olarak ayarlanırsa, sisteminiz açık ve koyu arasında geçiş yaptığında Markdown önizlemesinin teması da otomatik olarak açık ve koyu arasında geçiş yapar. Örneğin, geçerli önizleme temasını `github-light.css` olarak ayarladıysanız, sisteminiz koyu olduğunda önizleme teması otomatik olarak `github-dark.css` olarak değişir. false olarak ayarlanırsa, önizleme teması otomatik olarak değiştirilmez.",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "Düzenleyiciyle aynı temayı kullan (açık veya koyu). true olarak ayarlanırsa, VS Code açık ve koyu teması arasında geçiş yaptığınızda Markdown önizlemesinin teması da otomatik olarak açık ve koyu arasında geçiş yapar. Örneğin, geçerli önizleme temasını `github-light.css` olarak ayarladıysanız, VS Code koyu temasına geçtiğinizde önizleme teması otomatik olarak `github-dark.css` olarak değişir. false olarak ayarlanırsa, önizleme teması otomatik olarak değiştirilmez.",
    +  "markdown-preview-enhanced.enableTypographer.description": "smartypants ve diğer kullanışlı dönüşümleri etkinleştir.",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "Matematik ifadesi işleme yöntemini burada seçin. İsterseniz 'None' öğesini seçerek matematik işlemeyi devre dışı bırakabilirsiniz.",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "Özelleştirilmiş satır içi matematik ifadesi sınırlayıcıları kullan.",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "Özelleştirilmiş blok matematik ifadesi sınırlayıcıları kullan.",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "GFM Markdown dışa aktarımı (Markdown olarak kaydet) için matematik ifadesi işleme yöntemini seçin.",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "MathJax betik kaynağı. Varsayılan CDN'yi (MathJax v4) kullanmak için boş bırakın.",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "Wiki Bağlantısı sözdizimi desteğini etkinleştir. Daha fazla bilgiyi https://help.github.com/articles/adding-links-to-wikis/ adresinde bulabilirsiniz",
    +  "markdown-preview-enhanced.enableLinkify.description": "Markdown önizlemesinde URL benzeri metnin bağlantılara dönüştürülmesini etkinleştir veya devre dışı bırak.",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "İşaretlenirse, GitHub stili dikey çizgili wiki bağlantıları kullanırız, yani [[linkText|wikiLink]]. Aksi takdirde, orijinal Wikipedia stili olan [[wikiLink|linkText]] kullanırız.",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "emoji ve font-awesome eklentisini etkinleştir. Bu yalnızca markdown-it ayrıştırıcısında çalışır, pandoc ayrıştırıcısında çalışmaz.",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "Tablo hücrelerini birleştirmeyi desteklemek için genişletilmiş tablo sözdizimini etkinleştir.",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "CriticMarkup sözdizimini etkinleştir. Yalnızca markdown-it ayrıştırıcısında çalışır. Daha fazla bilgi için lütfen http://criticmarkup.com/users-guide.php adresine bakın.",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "Obsidian stili #tag sözdizimini etkinleştir. `#tag-name` (ve iç içe `#parent/child`) öğelerini tıklanabilir hap şeklinde çapalar olarak işler. VS Code'un etiketle önceden doldurulmuş 'Dosyalarda Ara' özelliğini açmak için bir etikete tıklayın.",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "crossnote'un bellek içi not dizinine yükleyeceği bir Markdown dosyasının maksimum boyutu (bayt). Sınırı aşan dosyalar çalışma alanı yenileme sırasında atlanır — otomatik tamamlama, geri bağlantılar veya etiket panelinde görünmezler, ancak yine de wiki bağlantısına tıklayarak açabilirsiniz. `.md` uzantılı bir günlük/veri dökümünün tüm içeriğini (ayrıştırılmış bir token ağacıyla birlikte) bellekte tutacağı patolojik durumları önler. Sınırı devre dışı bırakmak için `0` olarak ayarlayın.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "Bağlantının uzantısı yoksa wiki bağlantısındaki bağlantı için kullanılacak dosya uzantısı.",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "Yalnızca dosya adından oluşan wiki bağlantılarının (örneğin `[[Note]]`) bir dosya yoluna nasıl çözümleneceği.\n\n- `relative` — geçerli notun dizinine göre çözümler (varsayılan).\n- `shortest` — tüm notları dosya adına göre arar ve en kısa benzersiz yolu tercih eder (aynı dizinde eşitlik bozma ile). Obsidian stili.\n- `absolute` — not defteri/çalışma alanı kökünden çözümler.\n\n`/` ile başlayan bağlantılar, bu ayardan bağımsız olarak her zaman not defteri kökünden çözümlenir.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "Geçerli notun dizinine göre çözümler.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "Tüm notları dosya adına göre arar ve en kısa benzersiz yolu tercih eder.",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "Not defteri/çalışma alanı kökünden çözümler.",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "Wiki bağlantısındaki dosya adının büyük/küçük harf durumu. Değer `none` ise dosya adı değiştirilmez. Aksi takdirde dosya adı belirtilen biçime dönüştürülür. Daha fazla ayrıntı için https://www.npmjs.com/package/case-anything adresini okuyabilirsiniz.",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Front matter işleme seçeneği",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Mermaid teması, [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"] arasından birini seçebilirsiniz",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "Kod bloğu teması. `auto.css` seçilirse, geçerli önizleme temasına en uygun kod bloğu teması seçilir.",
    +  "markdown-preview-enhanced.previewTheme.description": "Önizleme Teması",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "Yok",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "RevealJS Sunum Teması",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "Bağlantılar için kabul edilen protokoller.",
    +  "markdown-preview-enhanced.imageFolderPath.description": "Görüntüleri kopyalamak için Görüntü Yardımcısı kullanıldığında, görüntüler varsayılan olarak kök görüntü klasörü yolu '/assets' içine kopyalanır",
    +  "markdown-preview-enhanced.imageUploader.description": "Görüntü yüklemek için farklı görüntü yükleyiciler seçebilirsiniz",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "Qiniu AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "Qiniu SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "Qiniu Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "Qiniu Domain",
    +  "markdown-preview-enhanced.printBackground.description": "Dosya dışa aktarımı için arka planın yazdırılıp yazdırılmayacağı. `false` olarak ayarlanırsa `github-light` önizleme teması kullanılır. Ayrıca tek tek dosyalar için front-matter içinde `print_background` ayarlayabilirsiniz.",
    +  "markdown-preview-enhanced.chromePath.description": "Puppeteer dışa aktarımı için kullanılan Chrome yürütülebilir dosyasının yolu. Boş bırakılması, yolun otomatik olarak bulunacağı anlamına gelir.",
    +  "markdown-preview-enhanced.imageMagickPath.description": "ImageMagick komut satırı yolu. `magick` veya `convert` olmalıdır. Boş bırakılması, yolun otomatik olarak bulunacağı anlamına gelir.",
    +  "markdown-preview-enhanced.pandocPath.description": "Pandoc yürütülebilir dosya yolu",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "markdown_yo yerel ikili dosyasının yolu. Ayarlandığında ve markdownParser 'markdown_yo' olduğunda, crossnote yerleşik WASM modülü yerine bu ikili dosyayı (stdin/stdout aracılığıyla) kullanır. Yerel ikili dosya ~300 KB altındaki dosyalar için daha hızlıdır; WASM çok büyük dosyalar için daha hızlıdır. $HOME ve ~ değişken ikamesini destekler. WASM'yi (varsayılan) kullanmak için boş bırakın.",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "İstediğiniz Pandoc Markdown çeşidi",
    +  "markdown-preview-enhanced.pandocArguments.description": "pandoc komutuna geçirilen argümanlar, örneğin [\"--smart\", \"--filter=/bin/exe\"]. Lütfen uzun argüman adlarını kullanın.",
    +  "markdown-preview-enhanced.latexEngine.description": "Pandoc dışa aktarımı ve latex kod parçası için varsayılan latex altyapısı.",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "Kod parçalarının çalıştırılmasını ve JavaScript dosyalarının içe aktarılmasını etkinleştirir.\n⚠️ Lütfen bu özelliği dikkatli kullanın çünkü güvenliğinizi riske atabilir! Betik çalıştırma etkinken birisi size kötü amaçlı kod içeren bir Markdown açtırırsa makineniz ele geçirilebilir.",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": "Ses/video bağlantılarının HTML5 gömülü audio/video etiketlerine dönüştürülmesini etkinleştirir.",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": "![]() sözdizimiyle video/ses gömmeyi etkinleştirir (varsayılan).",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "[]() sözdizimiyle video/ses gömmeyi etkinleştirir.",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "true olduğunda URL'lerde http:// şemasına sahip medyayı gömer. false olduğunda yoksayar ve gömmez.",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "audio etiketlerine geçirilecek HTML öznitelikleri.",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "video etiketlerine geçirilecek HTML öznitelikleri.",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "Puppeteer, belge dışa aktarımından önce milisaniye cinsinden belirli bir süre bekler.",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "puppeteer.launch({args: $puppeteerArgs}) öğesine geçirilen argümanlar",
    +  "markdown-preview-enhanced.plantumlServer.description": "İkili dosya yerine PlantUML sunucusu kullanarak işle. Yerleşik plantuml.jar ikili dosyasını kullanmak için boş bırakın (sistem yolunda `java` gereklidir). Örn.: \"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "VS Code varsayılan Markdown önizleme uzantısı düğmelerini gizle. Bu ayarın etkili olması için düzenleyicinin yeniden başlatılması gerekir.",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "jsDelivr CDN ana bilgisayarı. Örnek değerler: `cdn.jsdelivr.net`, `fastly.jsdelivr.net`, `gcore.jsdelivr.net`, `testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "plantuml.jar dosyasının mutlak yolu (sistem yolunda `java` gereklidir). https://plantuml.com/download adresinden indirebilirsiniz.",
    +  "markdown-preview-enhanced.krokiServer.description": "Kullanılacak Kroki sunucusunun URL'si.",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "wsd kod bloklarını işlemek için kullanılacak WebSequenceDiagrams sunucusunun URL'si.",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "WebSequenceDiagrams için API anahtarı. Daha büyük diyagram boyutları için gereklidir.",
    +  "markdown-preview-enhanced.d2Path.description": "D2 yürütülebilir dosyasının yolu. Varsayılan olarak `d2` (yani PATH'te bulunur). Web uzantısında desteklenmez.",
    +  "markdown-preview-enhanced.d2Layout.description": "d2 diyagramlarını işlemek için varsayılan D2 yerleşim altyapısı.",
    +  "markdown-preview-enhanced.d2Theme.description": "d2 diyagramlarını işlemek için varsayılan D2 teması.",
    +  "markdown-preview-enhanced.d2Sketch.description": "D2 diyagramlarını eskiz (elle çizilmiş) stilinde işle.",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Markdown dosya uzantıları. Markdown dosyası bağlam menüsünde önizleme düğmesinin gösterilip gösterilmeyeceğini belirlemek için kullanılır.",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "Önizlemede geri bağlantıları her zaman göster.",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "Bu seçeneğin etkinleştirilmesi, fareniz üzerinde olmadığı sürece önizlemedeki gereksiz arayüz öğelerini gizler.",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "Etkinleştirildiğinde, önizlemedeki bağlam menüsü varsayılan stil yerine VS Code'un tema renklerini ve yazı tipini devralır.",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "Önizlemedeki bir görüntüye tıklayarak tam ekran lightbox katmanında görüntüleyin. Kapatmak için Escape tuşuna basın veya arka plana tıklayın."
     }
    
  • package.nls.zh-cn.json+129 0 added
    @@ -0,0 +1,129 @@
    +{
    +  "displayName": "Markdown 增强预览",
    +  "description": " 这款插件意在让你拥有飘逸的 Markdown 写作体验",
    +  "customEditorPreviewDisplayName": "Markdown 增强预览",
    +  "markdown-preview-enhanced.openGraphView.title": "MPE:打开图形视图",
    +  "markdown-preview-enhanced.openPreviewToTheSide.title": "MPE:打开侧边预览",
    +  "markdown-preview-enhanced.openPreview.title": "MPE:打开预览",
    +  "markdown-preview-enhanced.openLockedPreviewToTheSide.title": "MPE:打开锁定的侧边预览",
    +  "markdown-preview-enhanced.togglePreviewLock.title": "MPE:切换预览锁定",
    +  "markdown-preview-enhanced.copyBlockReference.title": "MPE:复制块引用",
    +  "markdown-preview-enhanced.toggleScrollSync.title": "MPE:开关预览滑动同步",
    +  "markdown-preview-enhanced.toggleLiveUpdate.title": "MPE:开关预览实时更新",
    +  "markdown-preview-enhanced.toggleBreakOnSingleNewLine.title": "MPE:开关回车换行",
    +  "markdown-preview-enhanced.openImageHelper.title": "MPE:图片助手",
    +  "markdown-preview-enhanced.runAllCodeChunks.title": "MPE:运行所有代码块",
    +  "markdown-preview-enhanced.runCodeChunk.title": "MPE:运行代码块",
    +  "markdown-preview-enhanced.syncPreview.title": "MPE:同步预览",
    +  "markdown-preview-enhanced.customizeCss.title": "MPE:自定义样式(全局)",
    +  "markdown-preview-enhanced.customizeCssInWorkspace.title": "MPE:自定义样式(工作区)",
    +  "markdown-preview-enhanced.insertNewSlide.title": "MPE:插入新的幻灯片",
    +  "markdown-preview-enhanced.insertTable.title": "MPE:插入表格",
    +  "markdown-preview-enhanced.insertPagebreak.title": "MPE:插入断页符",
    +  "markdown-preview-enhanced.createTOC.title": "MPE:创建目录列表",
    +  "markdown-preview-enhanced.openConfigScript.title": "MPE:打开配置脚本(全局)",
    +  "markdown-preview-enhanced.openConfigScriptInWorkspace.title": "MPE:打开配置脚本(工作区)",
    +  "markdown-preview-enhanced.extendParser.title": "MPE:扩展 Parser(全局)",
    +  "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:扩展 Parser(工作区)",
    +  "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:自定义预览 HTML 头部(全局)",
    +  "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:自定义预览 HTML 头部(工作区)",
    +  "markdown-preview-enhanced.showUploadedImages.title": "MPE:显示图片上传历史",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "更改后需要重启。全局配置目录路径。留空则在 Windows 上使用 `$HOME/.crossnote`,或使用 `$XDG_CONFIG_HOME/.crossnote` 或 `$HOME/.local/state/crossnote` 作为配置路径。",
    +  "markdown-preview-enhanced.markdownParser.description": "要使用的 Markdown 解析器/渲染器。'markdown-it'(默认)为内置渲染器。'pandoc' 使用 Pandoc(需要安装 Pandoc;在 VS Code 网页版中不可用)。'markdown_yo' 使用高性能 WASM 渲染器(设置 markdownYoBinaryPath 时使用原生二进制;实验性)。",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "内置的 markdown-it 渲染器(默认)。",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "通过 Pandoc 渲染。需要安装 Pandoc。在 VS Code 网页版中不可用。",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "高性能渲染器(实验性)。默认使用 WASM,设置 markdownYoBinaryPath 时使用原生二进制。基于 token 的操作仍使用 markdown-it。",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "在 Markdown 中,单个换行符不会在生成的 HTML 中产生换行。但在 GitHub Flavored Markdown 中并非如此。启用此选项可让 Markdown 源中的单个换行在渲染的 HTML 中产生换行。",
    +  "markdown-preview-enhanced.scrollSync.description": "自动滚动同步。目前已部分支持。",
    +  "markdown-preview-enhanced.liveUpdate.description": "在源内容变化时实时重新渲染预览,无需保存源缓冲区。若禁用,则仅在缓冲区保存到磁盘时才重新渲染预览。",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "实时更新的防抖时间(毫秒)。较高的值可降低 CPU 占用,但响应可能变慢;较低的值反馈更及时,但可能影响性能。",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview**:所有编辑器只显示一个预览。\n- **Multiple Previews**:显示多个预览,每个编辑器拥有各自的预览。\n- **Previews Only**:不显示编辑器,只显示预览。你可以使用预览内的编辑器来编辑 Markdown。\n\n更改后需要重启。",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "自动显示正在编辑的 Markdown 的预览。",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "要从 `automaticallyShowPreviewOfMarkdownBeingEdited` 功能中排除的 URI scheme 列表(例如 `vscode-notebook-cell`)。匹配这些 scheme 的文件不会触发自动预览。",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "要从 `automaticallyShowPreviewOfMarkdownBeingEdited` 功能中排除的文件名模式列表(例如 `*.note.md`)。文件名匹配其中任意模式的文件不会触发自动预览。支持使用 `*` 作为通配符。匹配针对文件的基本名(而非完整路径)进行,且不区分大小写。",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "使用 `markdown-preview-enhanced.previewTheme` 设置。",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "跟随系统配色方案。若设为 true,则当系统在浅色与深色之间切换时,Markdown 预览主题会自动切换。例如,若当前预览主题设为 `github-light.css`,当系统为深色时,预览主题会自动切换为 `github-dark.css`。若设为 false,则预览主题不会自动更改。",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "使用与编辑器相同的主题(浅色或深色)。若设为 true,则当你在 VS Code 浅色与深色主题之间切换时,Markdown 预览主题会自动切换。例如,若当前预览主题设为 `github-light.css`,当你切换到 VS Code 深色主题时,预览主题会自动切换为 `github-dark.css`。若设为 false,则预览主题不会自动更改。",
    +  "markdown-preview-enhanced.enableTypographer.description": "启用 smartypants 及其他排版美化转换。",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "在此选择数学表达式的渲染方式。如果不需要,也可以选择 'None' 来禁用数学渲染。",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "使用自定义的行内数学表达式分隔符。",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "使用自定义的块级数学表达式分隔符。",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "为 GFM Markdown 导出(另存为 Markdown)选择数学表达式的渲染方式。",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "MathJax 脚本源。留空则使用默认 CDN(MathJax v4)。",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "启用 Wiki 链接语法支持。更多信息请参见 https://help.github.com/articles/adding-links-to-wikis/",
    +  "markdown-preview-enhanced.enableLinkify.description": "在 Markdown 预览中启用或禁用将类似 URL 的文本转换为链接。",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "若勾选,则使用 GitHub 风格的带管道符 Wiki 链接,即 [[linkText|wikiLink]];否则使用 [[wikiLink|linkText]](原始的 Wikipedia 风格)。",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "启用 emoji 和 font-awesome 插件。仅对 markdown-it 解析器有效,对 pandoc 解析器无效。",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "启用扩展表格语法以支持合并单元格。",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "启用 CriticMarkup 语法。仅对 markdown-it 解析器有效。更多信息请参见 http://criticmarkup.com/users-guide.php。",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "启用 Obsidian 风格的 #tag 标签语法。将 `#tag-name`(以及嵌套的 `#parent/child`)渲染为可点击的胶囊形锚点。点击标签会打开 VS Code 的“在文件中搜索”并预填该标签。",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "crossnote 载入内存笔记索引的 Markdown 文件的最大大小(字节)。超过上限的文件在工作区刷新时会被跳过——它们不会出现在自动补全、反向链接或标签面板中,但你仍可通过点击 Wiki 链接打开它们。这可避免某些极端情况:带有 `.md` 扩展名的日志/数据转储文件会将其全部内容(以及解析后的 token 树)常驻内存。设为 `0` 可禁用该上限。",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "当 Wiki 链接没有扩展名时,为其链接使用的文件扩展名。",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "如何将裸文件名的 Wiki 链接(例如 `[[Note]]`)解析为文件路径。\n\n- `relative` —— 相对于当前笔记所在目录解析(默认)。\n- `shortest` —— 按文件名搜索所有笔记,优先选择最短的唯一路径(同目录时优先)。Obsidian 风格。\n- `absolute` —— 从笔记本/工作区根目录解析。\n\n以 `/` 开头的链接始终从笔记本根目录解析,无论此设置如何。",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "相对于当前笔记所在目录解析。",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "按文件名搜索所有笔记,优先选择最短的唯一路径。",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "从笔记本/工作区根目录解析。",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "Wiki 链接中文件名的大小写。若值为 `none`,则不更改文件名;否则文件名将转换为指定的大小写形式。详情可阅读 https://www.npmjs.com/package/case-anything 。",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Front matter 渲染选项",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Mermaid 主题,可从 [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"] 中选择一个",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "代码块主题。若选择 `auto.css`,则会自动选择与当前预览主题最匹配的代码块主题。",
    +  "markdown-preview-enhanced.previewTheme.description": "预览主题",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "无",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "RevealJS 演示主题",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "链接所接受的协议。",
    +  "markdown-preview-enhanced.imageFolderPath.description": "使用图片助手复制图片时,默认会将图片复制到根图片文件夹路径 '/assets'",
    +  "markdown-preview-enhanced.imageUploader.description": "你可以选择不同的图床来上传图片",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "七牛 AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "七牛 SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "七牛 Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "七牛 Domain",
    +  "markdown-preview-enhanced.printBackground.description": "导出文件时是否打印背景。若设为 `false`,则使用 `github-light` 预览主题。你也可以在各个文件的 front-matter 中设置 `print_background`。",
    +  "markdown-preview-enhanced.chromePath.description": "Chrome 可执行文件路径,用于 Puppeteer 导出。留空表示自动查找路径。",
    +  "markdown-preview-enhanced.imageMagickPath.description": "ImageMagick 命令行路径。应为 `magick` 或 `convert`。留空表示自动查找路径。",
    +  "markdown-preview-enhanced.pandocPath.description": "Pandoc 可执行文件路径",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "markdown_yo 原生二进制文件的路径。当设置该项且 markdownParser 为 'markdown_yo' 时,crossnote 会使用该二进制(通过 stdin/stdout)而非内置的 WASM 模块。对于约 300 KB 以下的文件,原生二进制更快;对于超大文件,WASM 更快。支持 $HOME 和 ~ 变量替换。留空则使用 WASM(默认)。",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "你想使用的 Pandoc Markdown 风格",
    +  "markdown-preview-enhanced.pandocArguments.description": "传递给 pandoc 命令的参数,例如 [\"--smart\", \"--filter=/bin/exe\"]。请使用长参数名。",
    +  "markdown-preview-enhanced.latexEngine.description": "用于 Pandoc 导出和 latex 代码块的默认 latex 引擎。",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "启用执行代码块和导入 JavaScript 文件。\n⚠️ 请谨慎使用此功能,因为它可能带来安全风险!如果有人诱导你在启用脚本执行时打开包含恶意代码的 Markdown,你的机器可能被入侵。",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": "启用将音频/视频链接转换为 HTML5 嵌入的 audio/video 标签。",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": "启用使用 ![]() 语法嵌入视频/音频(默认)。",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "启用使用 []() 语法嵌入视频/音频。",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "为 true 时嵌入 URL 中使用 http:// 协议的媒体;为 false 时忽略且不嵌入它们。",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "传递给 audio 标签的 HTML 属性。",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "传递给 video 标签的 HTML 属性。",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "Puppeteer 在导出文档前等待的超时时间(毫秒)。",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "传递给 puppeteer.launch({args: $puppeteerArgs}) 的参数",
    +  "markdown-preview-enhanced.plantumlServer.description": "使用 PlantUML 服务器而非二进制进行渲染。留空则使用内置的 plantuml.jar 二进制(系统路径中需要有 `java`)。例如:\"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "隐藏 VS Code 默认 Markdown 预览扩展的按钮。此配置需要重启编辑器才能生效。",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "jsDelivr CDN 主机。示例值:`cdn.jsdelivr.net`、`fastly.jsdelivr.net`、`gcore.jsdelivr.net`、`testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "plantuml.jar 文件的绝对路径(系统路径中需要有 `java`)。你可以从 https://plantuml.com/download 下载。",
    +  "markdown-preview-enhanced.krokiServer.description": "要使用的 Kroki 服务器 URL。",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "用于渲染 wsd 代码块的 WebSequenceDiagrams 服务器 URL。",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "WebSequenceDiagrams 的 API 密钥。更大的图表尺寸需要它。",
    +  "markdown-preview-enhanced.d2Path.description": "D2 可执行文件路径。默认为 `d2`(即在 PATH 中查找)。网页版扩展不支持。",
    +  "markdown-preview-enhanced.d2Layout.description": "用于渲染 d2 图表的默认 D2 布局引擎。",
    +  "markdown-preview-enhanced.d2Theme.description": "用于渲染 d2 图表的默认 D2 主题。",
    +  "markdown-preview-enhanced.d2Sketch.description": "以手绘(sketch)风格渲染 D2 图表。",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Markdown 文件扩展名。用于决定是否在 Markdown 文件的右键菜单中显示预览按钮。",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "始终在预览中显示反向链接。",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "启用此选项将隐藏预览中不必要的 UI 元素,除非鼠标悬停其上。",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "启用后,预览中的右键菜单将继承 VS Code 的主题颜色和字体,而非默认样式。",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "点击预览中的图片可在全屏灯箱叠层中查看。按 Escape 或点击背景关闭。"
    +}
    
  • package.nls.zh.json+0 31 removed
    @@ -1,31 +0,0 @@
    -{
    -  "displayName": "Markdown 增强预览",
    -  "description": " 这款插件意在让你拥有飘逸的 Markdown 写作体验",
    -  "customEditorPreviewDisplayName": "Markdown 增强预览",
    -  "markdown-preview-enhanced.openGraphView.title": "MPE:打开图形视图",
    -  "markdown-preview-enhanced.openPreviewToTheSide.title": "MPE:打开侧边预览",
    -  "markdown-preview-enhanced.openPreview.title": "MPE:打开预览",
    -  "markdown-preview-enhanced.openLockedPreviewToTheSide.title": "MPE:打开锁定的侧边预览",
    -  "markdown-preview-enhanced.togglePreviewLock.title": "MPE:切换预览锁定",
    -  "markdown-preview-enhanced.copyBlockReference.title": "MPE:复制块引用",
    -  "markdown-preview-enhanced.toggleScrollSync.title": "MPE:开关预览滑动同步",
    -  "markdown-preview-enhanced.toggleLiveUpdate.title": "MPE:开关预览实时更新",
    -  "markdown-preview-enhanced.toggleBreakOnSingleNewLine.title": "MPE:开关回车换行",
    -  "markdown-preview-enhanced.openImageHelper.title": "MPE:图片助手",
    -  "markdown-preview-enhanced.runAllCodeChunks.title": "MPE:运行所有代码块",
    -  "markdown-preview-enhanced.runCodeChunk.title": "MPE:运行代码块",
    -  "markdown-preview-enhanced.syncPreview.title": "MPE:同步预览",
    -  "markdown-preview-enhanced.customizeCss.title": "MPE:自定义样式(全局)",
    -  "markdown-preview-enhanced.customizeCssInWorkspace.title": "MPE:自定义样式(工作区)",
    -  "markdown-preview-enhanced.insertNewSlide.title": "MPE:插入新的幻灯片",
    -  "markdown-preview-enhanced.insertTable.title": "MPE:插入表格",
    -  "markdown-preview-enhanced.insertPagebreak.title": "MPE:插入断页符",
    -  "markdown-preview-enhanced.createTOC.title": "MPE:创建目录列表",
    -  "markdown-preview-enhanced.openConfigScript.title": "MPE:打开配置脚本(全局)",
    -  "markdown-preview-enhanced.openConfigScriptInWorkspace.title": "MPE:打开配置脚本(工作区)",
    -  "markdown-preview-enhanced.extendParser.title": "MPE:扩展 Parser(全局)",
    -  "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:扩展 Parser(工作区)",
    -  "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:自定义预览 HTML 头部(全局)",
    -  "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:自定义预览 HTML 头部(工作区)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "MPE:显示图片上传历史"
    -}
    
  • package.nls.zh-tw.json+99 1 modified
    @@ -27,5 +27,103 @@
       "markdown-preview-enhanced.extendParserInWorkspace.title": "MPE:擴充 Parser(工作區)",
       "markdown-preview-enhanced.customizePreviewHtmlHead.title": "MPE:自訂預覽 HTML 頭部(全域)",
       "markdown-preview-enhanced.customizePreviewHtmlHeadInWorkspace.title": "MPE:自訂預覽 HTML 頭部(工作區)",
    -  "markdown-preview-enhanced.showUploadedImages.title": "MPE:顯示圖片上傳記錄"
    +  "markdown-preview-enhanced.showUploadedImages.title": "MPE:顯示圖片上傳記錄",
    +  "markdown-preview-enhanced.configPath.markdownDescription": "變更後需要重新啟動。全域設定目錄路徑。留空則在 Windows 上使用 `$HOME/.crossnote`,或使用 `$XDG_CONFIG_HOME/.crossnote` 或 `$HOME/.local/state/crossnote` 作為設定路徑。",
    +  "markdown-preview-enhanced.markdownParser.description": "要使用的 Markdown 解析器/渲染器。'markdown-it'(預設)為內建渲染器。'pandoc' 使用 Pandoc(需要安裝 Pandoc;在 VS Code 網頁版中不可用)。'markdown_yo' 使用高效能 WASM 渲染器(設定 markdownYoBinaryPath 時使用原生二進位;實驗性)。",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.0": "內建的 markdown-it 渲染器(預設)。",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.1": "透過 Pandoc 渲染。需要安裝 Pandoc。在 VS Code 網頁版中不可用。",
    +  "markdown-preview-enhanced.markdownParser.enumDescriptions.2": "高效能渲染器(實驗性)。預設使用 WASM,設定 markdownYoBinaryPath 時使用原生二進位。基於 token 的操作仍使用 markdown-it。",
    +  "markdown-preview-enhanced.breakOnSingleNewLine.description": "在 Markdown 中,單一換行字元不會在產生的 HTML 中產生換行。但在 GitHub Flavored Markdown 中並非如此。啟用此選項可讓 Markdown 原始碼中的單一換行在產生的 HTML 中產生換行。",
    +  "markdown-preview-enhanced.scrollSync.description": "自動捲動同步。目前已部分支援。",
    +  "markdown-preview-enhanced.liveUpdate.description": "在原始內容變更時即時重新渲染預覽,無需儲存原始緩衝區。若停用,則僅在緩衝區儲存到磁碟時才重新渲染預覽。",
    +  "markdown-preview-enhanced.liveUpdateDebounceMs.description": "即時更新的去抖動時間(毫秒)。較高的值可降低 CPU 佔用,但回應可能變慢;較低的值回饋更及時,但可能影響效能。",
    +  "markdown-preview-enhanced.previewMode.markdownDescription": "- **Single Preview**:所有編輯器只顯示一個預覽。\n- **Multiple Previews**:顯示多個預覽,每個編輯器擁有各自的預覽。\n- **Previews Only**:不顯示編輯器,只顯示預覽。你可以使用預覽內的編輯器來編輯 Markdown。\n\n變更後需要重新啟動。",
    +  "markdown-preview-enhanced.automaticallyShowPreviewOfMarkdownBeingEdited.description": "自動顯示正在編輯的 Markdown 的預覽。",
    +  "markdown-preview-enhanced.disableAutoPreviewForUriSchemes.markdownDescription": "要從 `automaticallyShowPreviewOfMarkdownBeingEdited` 功能中排除的 URI scheme 清單(例如 `vscode-notebook-cell`)。符合這些 scheme 的檔案不會觸發自動預覽。",
    +  "markdown-preview-enhanced.disableAutoPreviewForFilePatterns.markdownDescription": "要從 `automaticallyShowPreviewOfMarkdownBeingEdited` 功能中排除的檔案名稱模式清單(例如 `*.note.md`)。檔案名稱符合其中任一模式的檔案不會觸發自動預覽。支援使用 `*` 作為萬用字元。比對針對檔案的基本名稱(而非完整路徑)進行,且不區分大小寫。",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.0": "使用 `markdown-preview-enhanced.previewTheme` 設定。",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.1": "跟隨系統配色方案。若設為 true,則當系統在淺色與深色之間切換時,Markdown 預覽主題會自動切換。例如,若目前預覽主題設為 `github-light.css`,當系統為深色時,預覽主題會自動切換為 `github-dark.css`。若設為 false,則預覽主題不會自動變更。",
    +  "markdown-preview-enhanced.previewColorScheme.markdownEnumDescriptions.2": "使用與編輯器相同的主題(淺色或深色)。若設為 true,則當你在 VS Code 淺色與深色主題之間切換時,Markdown 預覽主題會自動切換。例如,若目前預覽主題設為 `github-light.css`,當你切換到 VS Code 深色主題時,預覽主題會自動切換為 `github-dark.css`。若設為 false,則預覽主題不會自動變更。",
    +  "markdown-preview-enhanced.enableTypographer.description": "啟用 smartypants 及其他排版美化轉換。",
    +  "markdown-preview-enhanced.mathRenderingOption.description": "在此選擇數學表達式的渲染方式。如果不需要,也可以選擇 'None' 來停用數學渲染。",
    +  "markdown-preview-enhanced.mathInlineDelimiters.description": "使用自訂的行內數學表達式分隔符號。",
    +  "markdown-preview-enhanced.mathBlockDelimiters.description": "使用自訂的區塊數學表達式分隔符號。",
    +  "markdown-preview-enhanced.mathRenderingOnlineService.description": "為 GFM Markdown 匯出(另存為 Markdown)選擇數學表達式的渲染方式。",
    +  "markdown-preview-enhanced.mathjaxScriptSrc.description": "MathJax 指令碼來源。留空則使用預設 CDN(MathJax v4)。",
    +  "markdown-preview-enhanced.enableWikiLinkSyntax.description": "啟用 Wiki 連結語法支援。更多資訊請參見 https://help.github.com/articles/adding-links-to-wikis/",
    +  "markdown-preview-enhanced.enableLinkify.description": "在 Markdown 預覽中啟用或停用將類似 URL 的文字轉換為連結。",
    +  "markdown-preview-enhanced.useGitHubStylePipedLink.description": "若勾選,則使用 GitHub 風格的帶管線符號 Wiki 連結,即 [[linkText|wikiLink]];否則使用 [[wikiLink|linkText]](原始的 Wikipedia 風格)。",
    +  "markdown-preview-enhanced.enableEmojiSyntax.description": "啟用 emoji 和 font-awesome 外掛。僅對 markdown-it 解析器有效,對 pandoc 解析器無效。",
    +  "markdown-preview-enhanced.enableExtendedTableSyntax.description": "啟用擴充表格語法以支援合併儲存格。",
    +  "markdown-preview-enhanced.enableCriticMarkupSyntax.description": "啟用 CriticMarkup 語法。僅對 markdown-it 解析器有效。更多資訊請參見 http://criticmarkup.com/users-guide.php。",
    +  "markdown-preview-enhanced.enableTagSyntax.description": "啟用 Obsidian 風格的 #tag 標籤語法。將 `#tag-name`(以及巢狀的 `#parent/child`)渲染為可點擊的膠囊形錨點。點擊標籤會開啟 VS Code 的「在檔案中搜尋」並預先填入該標籤。",
    +  "markdown-preview-enhanced.maxNoteFileSize.markdownDescription": "crossnote 載入記憶體筆記索引的 Markdown 檔案的最大大小(位元組)。超過上限的檔案在工作區重新整理時會被略過——它們不會出現在自動完成、反向連結或標籤面板中,但你仍可透過點擊 Wiki 連結開啟它們。這可避免某些極端情況:帶有 `.md` 副檔名的記錄/資料傾印檔案會將其全部內容(以及解析後的 token 樹)常駐記憶體。設為 `0` 可停用該上限。",
    +  "markdown-preview-enhanced.wikiLinkTargetFileExtension.markdownDescription": "當 Wiki 連結沒有副檔名時,為其連結使用的檔案副檔名。",
    +  "markdown-preview-enhanced.wikiLinkResolution.markdownDescription": "如何將裸檔名的 Wiki 連結(例如 `[[Note]]`)解析為檔案路徑。\n\n- `relative` —— 相對於目前筆記所在目錄解析(預設)。\n- `shortest` —— 依檔案名稱搜尋所有筆記,優先選擇最短的唯一路徑(同目錄時優先)。Obsidian 風格。\n- `absolute` —— 從筆記本/工作區根目錄解析。\n\n以 `/` 開頭的連結一律從筆記本根目錄解析,無論此設定為何。",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.0": "相對於目前筆記所在目錄解析。",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.1": "依檔案名稱搜尋所有筆記,優先選擇最短的唯一路徑。",
    +  "markdown-preview-enhanced.wikiLinkResolution.enumDescriptions.2": "從筆記本/工作區根目錄解析。",
    +  "markdown-preview-enhanced.wikiLinkTargetFileNameChangeCase.markdownDescription": "Wiki 連結中檔案名稱的大小寫。若值為 `none`,則不變更檔案名稱;否則檔案名稱將轉換為指定的大小寫形式。詳情可閱讀 https://www.npmjs.com/package/case-anything 。",
    +  "markdown-preview-enhanced.frontMatterRenderingOption.description": "Front matter 渲染選項",
    +  "markdown-preview-enhanced.mermaidTheme.description": "Mermaid 主題,可從 [\"mermaid.css\", \"mermaid.dark.css\", \"mermaid.forest.css\"] 中選擇一個",
    +  "markdown-preview-enhanced.codeBlockTheme.description": "程式碼區塊主題。若選擇 `auto.css`,則會自動選擇與目前預覽主題最相符的程式碼區塊主題。",
    +  "markdown-preview-enhanced.previewTheme.description": "預覽主題",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.0": "Atom Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.1": "Atom Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.2": "Atom Material",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.3": "GitHub Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.4": "GitHub Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.5": "Gothic",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.6": "Medium",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.7": "Monokai",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.8": "Newsprint",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.9": "Night",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.10": "無",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.11": "One Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.12": "One Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.13": "Solarized Dark",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.14": "Solarized Light",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.15": "VS Code",
    +  "markdown-preview-enhanced.previewTheme.markdownEnumDescriptions.16": "Vue",
    +  "markdown-preview-enhanced.revealjsTheme.description": "RevealJS 簡報主題",
    +  "markdown-preview-enhanced.protocolsWhiteList.description": "連結所接受的通訊協定。",
    +  "markdown-preview-enhanced.imageFolderPath.description": "使用圖片助手複製圖片時,預設會將圖片複製到根圖片資料夾路徑 '/assets'",
    +  "markdown-preview-enhanced.imageUploader.description": "你可以選擇不同的圖片上傳工具來上傳圖片",
    +  "markdown-preview-enhanced.qiniuAccessKey.description": "七牛 AccessKey",
    +  "markdown-preview-enhanced.qiniuSecretKey.description": "七牛 SecretKey",
    +  "markdown-preview-enhanced.qiniuBucket.description": "七牛 Bucket",
    +  "markdown-preview-enhanced.qiniuDomain.description": "七牛 Domain",
    +  "markdown-preview-enhanced.printBackground.description": "匯出檔案時是否列印背景。若設為 `false`,則使用 `github-light` 預覽主題。你也可以在各個檔案的 front-matter 中設定 `print_background`。",
    +  "markdown-preview-enhanced.chromePath.description": "Chrome 可執行檔路徑,用於 Puppeteer 匯出。留空表示自動尋找路徑。",
    +  "markdown-preview-enhanced.imageMagickPath.description": "ImageMagick 命令列路徑。應為 `magick` 或 `convert`。留空表示自動尋找路徑。",
    +  "markdown-preview-enhanced.pandocPath.description": "Pandoc 可執行檔路徑",
    +  "markdown-preview-enhanced.markdownYoBinaryPath.description": "markdown_yo 原生二進位檔案的路徑。當設定該項且 markdownParser 為 'markdown_yo' 時,crossnote 會使用該二進位(透過 stdin/stdout)而非內建的 WASM 模組。對於約 300 KB 以下的檔案,原生二進位更快;對於超大檔案,WASM 更快。支援 $HOME 和 ~ 變數取代。留空則使用 WASM(預設)。",
    +  "markdown-preview-enhanced.pandocMarkdownFlavor.description": "你想使用的 Pandoc Markdown 風格",
    +  "markdown-preview-enhanced.pandocArguments.description": "傳遞給 pandoc 命令的參數,例如 [\"--smart\", \"--filter=/bin/exe\"]。請使用長參數名稱。",
    +  "markdown-preview-enhanced.latexEngine.description": "用於 Pandoc 匯出和 latex 程式碼區塊的預設 latex 引擎。",
    +  "markdown-preview-enhanced.enableScriptExecution.description": "啟用執行程式碼區塊和匯入 JavaScript 檔案。\n⚠️ 請謹慎使用此功能,因為它可能帶來安全風險!如果有人誘導你在啟用指令碼執行時開啟包含惡意程式碼的 Markdown,你的電腦可能遭到入侵。",
    +  "markdown-preview-enhanced.enableHTML5Embed.description": "啟用將音訊/影片連結轉換為 HTML5 嵌入的 audio/video 標籤。",
    +  "markdown-preview-enhanced.HTML5EmbedUseImageSyntax.description": "啟用使用 ![]() 語法嵌入影片/音訊(預設)。",
    +  "markdown-preview-enhanced.HTML5EmbedUseLinkSyntax.description": "啟用使用 []() 語法嵌入影片/音訊。",
    +  "markdown-preview-enhanced.HTML5EmbedIsAllowedHttp.description": "為 true 時嵌入 URL 中使用 http:// 通訊協定的媒體;為 false 時忽略且不嵌入它們。",
    +  "markdown-preview-enhanced.HTML5EmbedAudioAttributes.description": "傳遞給 audio 標籤的 HTML 屬性。",
    +  "markdown-preview-enhanced.HTML5EmbedVideoAttributes.description": "傳遞給 video 標籤的 HTML 屬性。",
    +  "markdown-preview-enhanced.puppeteerWaitForTimeout.description": "Puppeteer 在匯出文件前等待的逾時時間(毫秒)。",
    +  "markdown-preview-enhanced.puppeteerArgs.description": "傳遞給 puppeteer.launch({args: $puppeteerArgs}) 的參數",
    +  "markdown-preview-enhanced.plantumlServer.description": "使用 PlantUML 伺服器而非二進位進行渲染。留空則使用內建的 plantuml.jar 二進位(系統路徑中需要有 `java`)。例如:\"http://localhost:8080/svg/\"",
    +  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons.description": "隱藏 VS Code 預設 Markdown 預覽擴充功能的按鈕。此設定需要重新啟動編輯器才能生效。",
    +  "markdown-preview-enhanced.jsdelivrCdnHost.markdownDescription": "jsDelivr CDN 主機。範例值:`cdn.jsdelivr.net`、`fastly.jsdelivr.net`、`gcore.jsdelivr.net`、`testingcf.jsdelivr.net`",
    +  "markdown-preview-enhanced.plantumlJarPath.description": "plantuml.jar 檔案的絕對路徑(系統路徑中需要有 `java`)。你可以從 https://plantuml.com/download 下載。",
    +  "markdown-preview-enhanced.krokiServer.description": "要使用的 Kroki 伺服器 URL。",
    +  "markdown-preview-enhanced.webSequenceDiagramsServer.description": "用於渲染 wsd 程式碼區塊的 WebSequenceDiagrams 伺服器 URL。",
    +  "markdown-preview-enhanced.webSequenceDiagramsApiKey.description": "WebSequenceDiagrams 的 API 金鑰。更大的圖表尺寸需要它。",
    +  "markdown-preview-enhanced.d2Path.description": "D2 可執行檔路徑。預設為 `d2`(即在 PATH 中尋找)。網頁版擴充功能不支援。",
    +  "markdown-preview-enhanced.d2Layout.description": "用於渲染 d2 圖表的預設 D2 版面配置引擎。",
    +  "markdown-preview-enhanced.d2Theme.description": "用於渲染 d2 圖表的預設 D2 主題。",
    +  "markdown-preview-enhanced.d2Sketch.description": "以手繪(sketch)風格渲染 D2 圖表。",
    +  "markdown-preview-enhanced.markdownFileExtensions.description": "Markdown 檔案副檔名。用於決定是否在 Markdown 檔案的右鍵選單中顯示預覽按鈕。",
    +  "markdown-preview-enhanced.alwaysShowBacklinksInPreview.description": "一律在預覽中顯示反向連結。",
    +  "markdown-preview-enhanced.enablePreviewZenMode.description": "啟用此選項將隱藏預覽中不必要的 UI 元素,除非滑鼠停留其上。",
    +  "markdown-preview-enhanced.useVSCodeThemeForContextMenu.description": "啟用後,預覽中的右鍵選單將繼承 VS Code 的主題顏色和字型,而非預設樣式。",
    +  "markdown-preview-enhanced.enableImageLightbox.description": "點擊預覽中的圖片可在全螢幕燈箱疊層中檢視。按 Escape 或點擊背景關閉。"
     }
    
  • yarn.lock+10 4 modified
    @@ -2534,10 +2534,10 @@ cross-spawn@^7.0.3, cross-spawn@^7.0.6:
         shebang-command "^2.0.0"
         which "^2.0.1"
     
    -crossnote@^0.9.28:
    -  version "0.9.28"
    -  resolved "https://registry.yarnpkg.com/crossnote/-/crossnote-0.9.28.tgz#3bab68f4dfe1ca08c4280122e3dd9927943c3e0d"
    -  integrity sha512-9AaTgWYWxCN5Qb8f1hlMfb9U3UE0v086E6ictZa5xNBA+z8PMUcgayXSLmBPGfZv3u1hugHSaQByMj69RuF2MQ==
    +crossnote@0.9.29:
    +  version "0.9.29"
    +  resolved "https://registry.yarnpkg.com/crossnote/-/crossnote-0.9.29.tgz#18de19bfdcbf036df5caa709d3fe7e66ad48ff3c"
    +  integrity sha512-HKTPPuisnRFk4Mip1W/tMn0ZxnXGGm9fqInIb+rUQeEqiB5udLstlf/5i7ksSdJN8qCw15DgCoJ6y5eMNil4Pw==
       dependencies:
         "@headlessui/react" "^1.7.17"
         "@heroicons/react" "^2.0.18"
    @@ -2577,6 +2577,7 @@ crossnote@^0.9.28:
         ignore "^7.0.5"
         imagemagick-cli "^0.5.0"
         jquery "^3.7.1"
    +    json5 "^2.2.3"
         katex "^0.16.47"
         less "^4.2.0"
         markdown-it "^14.1.1"
    @@ -5427,6 +5428,11 @@ json-stable-stringify-without-jsonify@^1.0.1:
       resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
       integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
     
    +json5@^2.2.3:
    +  version "2.2.3"
    +  resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
    +  integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
    +
     jsonfile@^4.0.0:
       version "4.0.0"
       resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
    
5588ca2121c3

0.9.29 (#442)

https://github.com/shd101wyy/crossnoteYiyi WangJun 5, 2026via nvd-ref
28 files changed · +1366 38
  • CHANGELOG.md+11 4 modified
    @@ -2,7 +2,14 @@
     
     Please visit https://github.com/shd101wyy/vscode-markdown-preview-enhanced/releases for the more changelog
     
    -## [Unreleased]
    +## [0.9.29] - 2026-06-05
    +
    +### Bug fixes
    +
    +- **Harden external file/link opening against command injection** — Opening links and files from the preview no longer goes through a shell, and untrusted inputs (the diagram `filename` attribute, imported file paths, and the `latex_engine` code-chunk attribute) are passed as literal arguments or validated before use. This closes a security issue affecting Windows. Thanks to @byte16384 for the responsible disclosure.
    +- **Eliminate arbitrary code execution in WaveDrom rendering** — WaveDrom diagrams were parsed by evaluating untrusted markdown content with `eval()`, enabling arbitrary JavaScript execution. This affected every render path: the live preview (`window.eval`), and presentation mode plus HTML export (the bundled `WaveDrom.ProcessAll()`/`eva()` helpers). The live preview now parses with `JSON5.parse()`, and — because a malicious `<script type="WaveDrom">` can also be injected via raw HTML in markdown — the HTML sanitizer now validates and normalizes every WaveDrom data script to inert strict JSON, so no downstream `eval`/`ProcessAll` can execute attacker-controlled code. Fixes the security vulnerability reported in [vscode-mpe#2315](https://github.com/shd101wyy/vscode-markdown-preview-enhanced/issues/2315).
    +- **Replace `interpretJS` with `JSON5.parse` in Bitfield renderer** — Bitfield fenced code blocks were parsed using `interpretJS()` which evaluates user input via `vm.runInNewContext`, enabling arbitrary code execution on the server side. Replaced with `JSON5.parse()` since bitfield register definitions are purely data (arrays of objects).
    +- **Improve MathJax 4 rendering performance** — MathJax 4's combined `tex-mml-chtml` component runs accessibility _semantic enrichment_ (the speech-rule-engine) on every typeset, which dominates per-formula cost and made formula-heavy previews re-render slowly on each edit (measured ~890 ms vs ~42 ms for 127 formulas in Chrome — a ~21× difference). Semantic enrichment is now disabled by default (`options.enableEnrichment: false`), restoring MathJax-3-like performance. Because MathJax ignores this flag when set in the config block, the engine re-applies the configured a11y toggles onto the live `MathDocument` via a `startup.ready` hook; users who need screen-reader speech output can set `enableEnrichment: true` in their `mathjaxConfig`. Addresses [vscode-mpe#2312](https://github.com/shd101wyy/vscode-markdown-preview-enhanced/issues/2312).
     
     ## [0.9.28] - 2026-05-24
     
    @@ -239,12 +246,12 @@ The eager in-memory note cache is now slim: it holds metadata (title, aliases, f
     
     ### New features
     
    -- Add markdown-it callout feature with styling https://github.com/shd101wyy/crossnote/pull/387 by [@EmmetZ](https://github.com/EmmetZ).
    -- Add WebSequenceDiagrams support in `wsd` code blocks https://github.com/shd101wyy/vscode-markdown-preview-enhanced/pull/2228 by [@smhanov](https://github.com/smhanov).
    +- Add markdown-it callout feature with styling https://github.com/shd101wyy/crossnote/pull/387 by @EmmetZ.
    +- Add WebSequenceDiagrams support in `wsd` code blocks https://github.com/shd101wyy/vscode-markdown-preview-enhanced/pull/2228 by @smhanov.
     
     ### Bug fixes
     
    -- Remove the wrapper of custom head in HTML page https://github.com/shd101wyy/crossnote/pull/386 by [@TanShun](https://github.com/TanShun).
    +- Remove the wrapper of custom head in HTML page https://github.com/shd101wyy/crossnote/pull/386 by @TanShun.
     
     ### Security
     
    
  • .github/workflows/test.yml+37 0 modified
    @@ -50,3 +50,40 @@ jobs:
     
           - name: Build typedoc
             run: pnpm typedoc
    +
    +  browser-test:
    +    name: Browser tests (MathJax)
    +    runs-on: ubuntu-latest
    +    steps:
    +      - name: Check out code
    +        uses: actions/checkout@v5
    +        with:
    +          fetch-depth: 0
    +
    +      - name: Install pnpm
    +        uses: pnpm/action-setup@v4
    +
    +      - name: Install nodejs
    +        uses: actions/setup-node@v6
    +        with:
    +          cache: pnpm
    +          node-version-file: .tool-versions
    +
    +      - name: Install dependencies
    +        run: pnpm install
    +
    +      - name: Install Playwright Chromium
    +        run: pnpm exec playwright install --with-deps chromium
    +
    +      - name: Run browser tests
    +        # Real-Chromium tests for the client-side MathJax pipeline: equation
    +        # numbering across re-renders and a11y-enrichment performance (#2312).
    +        run: pnpm test:browser
    +
    +      - name: Upload Playwright report on failure
    +        if: ${{ failure() }}
    +        uses: actions/upload-artifact@v4
    +        with:
    +          name: playwright-report
    +          path: playwright-report/
    +          retention-days: 7
    
  • .gitignore+7 0 modified
    @@ -6,6 +6,7 @@ out
     test.js
     test.mjs
     .direnv
    +.codegraph
     tsconfig.tsbuildinfo
     pnpm-debug.log
     .mume
    @@ -17,3 +18,9 @@ styles/**/*.css
     !styles/markdown-it-callout.css
     !styles/twemoji.css
     docs
    +
    +# Playwright browser-test artifacts
    +/test-results
    +/playwright-report
    +/blob-report
    +/playwright/.cache
    
  • jest.config.js+3 0 modified
    @@ -9,5 +9,8 @@ module.exports = {
       transformIgnorePatterns: ['/node_modules/'],
       roots: ['test'],
       testMatch: ['**/?(*.)(spec|test).(j|t)s?(x)'],
    +  // Browser tests under test/browser run with Playwright (`pnpm test:browser`),
    +  // not jest — they need a real Chromium to exercise MathJax typesetting.
    +  testPathIgnorePatterns: ['/node_modules/', '/test/browser/'],
       testEnvironment: 'node',
     };
    
  • package.json+5 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "crossnote",
    -  "version": "0.9.28",
    +  "version": "0.9.29",
       "description": "A powerful markdown notebook tool",
       "keywords": [
         "markdown"
    @@ -43,6 +43,7 @@
         "prepare": "husky",
         "prepublish": "pnpm build",
         "test": "jest --no-coverage",
    +    "test:browser": "playwright test",
         "test:coverage": "jest",
         "typedoc": "typedoc src/index.ts"
       },
    @@ -103,6 +104,7 @@
         "ignore": "^7.0.5",
         "imagemagick-cli": "^0.5.0",
         "jquery": "^3.7.1",
    +    "json5": "^2.2.3",
         "katex": "^0.16.47",
         "less": "^4.2.0",
         "markdown-it": "^14.1.1",
    @@ -151,6 +153,7 @@
         "@babel/preset-react": "^7.26.3",
         "@babel/preset-typescript": "^7.26.0",
         "@eslint/js": "^10.0.1",
    +    "@playwright/test": "^1.60.0",
         "@simbathesailor/use-what-changed": "^2.0.0",
         "@types/crypto-js": "^4.1.1",
         "@types/d3-color": "^3.1.3",
    @@ -206,6 +209,7 @@
         "jest-environment-jsdom": "^30.3.0",
         "jsdom": "^23.2.0",
         "lint-staged": "^16.4.0",
    +    "mathjax": "^4.1.2",
         "postcss": "^8.4.29",
         "prettier": "^3.8.3",
         "prettier-plugin-packagejson": "^3.0.2",
    
  • playwright.config.ts+36 0 added
    @@ -0,0 +1,36 @@
    +import { defineConfig, devices } from '@playwright/test';
    +
    +/**
    + * Playwright config for the browser-backed tests under `test/browser`.
    + *
    + * These exercise the client-side MathJax pipeline in a real Chromium so we can
    + * lock in behavior that jsdom cannot reproduce (MathJax's speech-rule-engine
    + * worker, equation numbering across re-renders). Run with `pnpm test:browser`.
    + *
    + * In CI, Chromium is provided by `playwright install --with-deps chromium`.
    + * Locally (e.g. on NixOS where Playwright's bundled Chromium can't find system
    + * libs), point at a system browser via `PLAYWRIGHT_CHROMIUM_EXECUTABLE`.
    + */
    +const executablePath = process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE || undefined;
    +
    +export default defineConfig({
    +  testDir: './test/browser',
    +  fullyParallel: false,
    +  forbidOnly: !!process.env.CI,
    +  retries: process.env.CI ? 1 : 0,
    +  workers: 1,
    +  reporter: process.env.CI ? 'github' : 'list',
    +  use: {
    +    ...devices['Desktop Chrome'],
    +    launchOptions: executablePath ? { executablePath } : {},
    +  },
    +  projects: [
    +    {
    +      name: 'chromium',
    +      use: {
    +        ...devices['Desktop Chrome'],
    +        launchOptions: executablePath ? { executablePath } : {},
    +      },
    +    },
    +  ],
    +});
    
  • pnpm-lock.yaml+56 0 modified
    @@ -122,6 +122,9 @@ importers:
           jquery:
             specifier: ^3.7.1
             version: 3.7.1
    +      json5:
    +        specifier: ^2.2.3
    +        version: 2.2.3
           katex:
             specifier: ^0.16.47
             version: 0.16.47
    @@ -261,6 +264,9 @@ importers:
           '@eslint/js':
             specifier: ^10.0.1
             version: 10.0.1(eslint@10.2.1(jiti@1.21.7))
    +      '@playwright/test':
    +        specifier: ^1.60.0
    +        version: 1.60.0
           '@simbathesailor/use-what-changed':
             specifier: ^2.0.0
             version: 2.0.0(react@18.3.1)
    @@ -426,6 +432,9 @@ importers:
           lint-staged:
             specifier: ^16.4.0
             version: 16.4.0
    +      mathjax:
    +        specifier: ^4.1.2
    +        version: 4.1.2
           postcss:
             specifier: ^8.4.29
             version: 8.5.10
    @@ -1736,6 +1745,9 @@ packages:
         peerDependencies:
           tslib: '2'
     
    +  '@mathjax/mathjax-newcm-font@4.1.2':
    +    resolution: {integrity: sha512-lZHMjNP2XbABHA3kVn40rbse5ERUeMEmrGH03qLkCwxq4/5Z/eNLr0akw1MmQcqTwCbvkx1BFcmJ7RCfbRlw3Q==}
    +
       '@mdi/js@7.4.47':
         resolution: {integrity: sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==}
     
    @@ -1771,6 +1783,11 @@ packages:
         resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
         engines: {node: '>=14'}
     
    +  '@playwright/test@1.60.0':
    +    resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==}
    +    engines: {node: '>=18'}
    +    hasBin: true
    +
       '@prinsss/dvi2html@0.0.1':
         resolution: {integrity: sha512-AdlM+1uAXH278q50vfpwIU7ykA5FKuxi6mx5haGZCmVTeNw6nxcbfyTIBRmlviesu4W+YJeFFfdv+gJ68O47aw==}
     
    @@ -3396,6 +3413,11 @@ packages:
       fs.realpath@1.0.0:
         resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
     
    +  fsevents@2.3.2:
    +    resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
    +    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
    +    os: [darwin]
    +
       fsevents@2.3.3:
         resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
         engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
    @@ -4342,6 +4364,9 @@ packages:
         resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
         engines: {node: '>= 0.4'}
     
    +  mathjax@4.1.2:
    +    resolution: {integrity: sha512-EQDS8xBpVg179BXoLeZ9JlwUFftOC5qylw20UlAMDhrTuooENigOocY79aNkkFSyvj/AST/89ZAo12+r5bPI4w==}
    +
       md5@2.3.0:
         resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
     
    @@ -4741,6 +4766,16 @@ packages:
       plantuml-encoder@1.4.0:
         resolution: {integrity: sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==}
     
    +  playwright-core@1.60.0:
    +    resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==}
    +    engines: {node: '>=18'}
    +    hasBin: true
    +
    +  playwright@1.60.0:
    +    resolution: {integrity: sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==}
    +    engines: {node: '>=18'}
    +    hasBin: true
    +
       plugin-error@1.0.1:
         resolution: {integrity: sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==}
         engines: {node: '>= 0.10'}
    @@ -7387,6 +7422,8 @@ snapshots:
           '@jsonjoy.com/codegen': 17.67.0(tslib@2.8.1)
           tslib: 2.8.1
     
    +  '@mathjax/mathjax-newcm-font@4.1.2': {}
    +
       '@mdi/js@7.4.47': {}
     
       '@mdi/react@1.6.1':
    @@ -7423,6 +7460,10 @@ snapshots:
       '@pkgjs/parseargs@0.11.0':
         optional: true
     
    +  '@playwright/test@1.60.0':
    +    dependencies:
    +      playwright: 1.60.0
    +
       '@prinsss/dvi2html@0.0.1':
         dependencies:
           buffer: 6.0.3
    @@ -9356,6 +9397,9 @@ snapshots:
     
       fs.realpath@1.0.0: {}
     
    +  fsevents@2.3.2:
    +    optional: true
    +
       fsevents@2.3.3:
         optional: true
     
    @@ -10583,6 +10627,10 @@ snapshots:
     
       math-intrinsics@1.1.0: {}
     
    +  mathjax@4.1.2:
    +    dependencies:
    +      '@mathjax/mathjax-newcm-font': 4.1.2
    +
       md5@2.3.0:
         dependencies:
           charenc: 0.0.2
    @@ -11001,6 +11049,14 @@ snapshots:
     
       plantuml-encoder@1.4.0: {}
     
    +  playwright-core@1.60.0: {}
    +
    +  playwright@1.60.0:
    +    dependencies:
    +      playwright-core: 1.60.0
    +    optionalDependencies:
    +      fsevents: 2.3.2
    +
       plugin-error@1.0.1:
         dependencies:
           ansi-colors: 1.1.0
    
  • src/converters/process-graphs.ts+22 4 modified
    @@ -13,7 +13,7 @@ import * as magick from '../tools/magick';
     import * as mermaidAPI from '../tools/mermaid';
     import * as sharp from '../tools/sharp';
     import * as wavedromAPI from '../tools/wavedrom';
    -import { extractCommandFromBlockInfo } from '../utility';
    +import { extractCommandFromBlockInfo, sanitizeImageFilename } from '../utility';
     
     export async function processGraphs(
       text: string,
    @@ -139,6 +139,17 @@ export async function processGraphs(
         }
       }
     
    +  // Resolve a sanitized output image name to an absolute path. A leading `/`
    +  // means "relative to the project root" (MPE's imageFolderPath convention),
    +  // not a filesystem-absolute path; otherwise it's relative to the image output
    +  // directory.
    +  function resolveOutputImagePath(name: string): string {
    +    if (name.startsWith('/')) {
    +      return path.resolve(projectDirectoryPath, '.' + name);
    +    }
    +    return path.resolve(imageDirectoryPath, name);
    +  }
    +
       async function convertSVGToPNGFile(
         outFileName: string = '',
         svg: string,
    @@ -150,11 +161,14 @@ export async function processGraphs(
         altName: string,
         optionsStr: string,
       ) {
    +    // The filename comes from untrusted markdown and ends up in a converter
    +    // that shells out; reject anything but a safe relative name.
    +    outFileName = sanitizeImageFilename(outFileName);
         if (!outFileName) {
           outFileName = imageFilePrefix + imgCount + '.png';
         }
     
    -    const pngFilePath = path.resolve(imageDirectoryPath, outFileName);
    +    const pngFilePath = resolveOutputImagePath(outFileName);
         if (notebook.config.imageMagickPath) {
           // use `magick`
           await magick.svgElementToPNGFile(
    @@ -298,11 +312,15 @@ export async function processGraphs(
         } else if (def.match(/^mermaid/)) {
           // mermaid-cli Ver.8.4.8 has a bug, render in png https://github.com/mermaid-js/mermaid/issues/664
           try {
    -        let pngFileName = options['filename'] as string | undefined;
    +        // `filename` is untrusted markdown and is passed to mermaid-cli, which
    +        // is spawned with `shell: true`; reject shell-unsafe names.
    +        let pngFileName = sanitizeImageFilename(
    +          options['filename'] as string | undefined,
    +        );
             if (!pngFileName) {
               pngFileName = imageFilePrefix + imgCount + '.png';
             }
    -        const pngFilePath = path.resolve(imageDirectoryPath, pngFileName);
    +        const pngFilePath = resolveOutputImagePath(pngFileName);
             imgCount++;
             await mermaidAPI.mermaidToPNG(
               content,
    
  • src/markdown-engine/index.ts+5 4 modified
    @@ -44,6 +44,7 @@ import enhanceWithResolvedImagePaths from '../render-enhancers/resolved-image-pa
     import * as utility from '../utility';
     import { removeFileProtocol } from '../utility';
     import HeadingIdGenerator from './heading-id-generator';
    +import { buildMathJaxConfigScript } from './mathjax-config';
     import { sanitizeRenderedHTML } from './sanitize';
     import { HeadingData, generateSidebarToCHTML } from './toc';
     import { transformMarkdown } from './transformer';
    @@ -366,9 +367,9 @@ export class MarkdownEngine {
             startupConfig['elements'] = ['.hidden-preview']; // Only render on this element
           }
     
    -      scripts += `<script type="text/javascript"> window.MathJax = (${JSON.stringify(
    +      scripts += `<script type="text/javascript"> ${buildMathJaxConfigScript(
             mathJaxConfig,
    -      )}); </script>`;
    +      )} </script>`;
           scripts += `<script type="text/javascript" defer src="${this.notebook.config.mathjaxScriptSrc}" charset="UTF-8"></script>`;
         }
     
    @@ -972,7 +973,7 @@ window["initRevealPresentation"] = async function() {
           if (options.offline) {
             mathStyle = `
             <script type="text/javascript">
    -          window.MathJax = (${JSON.stringify(mathJaxConfig)});
    +          ${buildMathJaxConfigScript(mathJaxConfig)}
             </script>
             <script type="text/javascript" defer src="${
               this.notebook.config.mathjaxScriptSrc
    @@ -981,7 +982,7 @@ window["initRevealPresentation"] = async function() {
           } else {
             mathStyle = `
             <script type="text/javascript">
    -          window.MathJax = (${JSON.stringify(mathJaxConfig)});
    +          ${buildMathJaxConfigScript(mathJaxConfig)}
             </script>
             <script type="text/javascript" defer src="${
               this.notebook.config.mathjaxScriptSrc
    
  • src/markdown-engine/mathjax-config.ts+67 0 added
    @@ -0,0 +1,67 @@
    +/**
    + * Helpers for emitting the client-side MathJax configuration.
    + *
    + * Kept in a dependency-free module so it can be unit-tested (jest) and
    + * exercised in a real browser (Playwright) without pulling in the whole
    + * markdown engine.
    + */
    +
    +// a11y document options that MathJax 4's combined component resets to their
    +// defaults during startup. The `startup.ready` hook below re-applies whichever
    +// of these the user configured onto the live MathDocument.
    +const A11Y_OPTION_KEYS = [
    +  'enableEnrichment',
    +  'enableSpeech',
    +  'enableBraille',
    +  'enableComplexity',
    +  'enableExplorer',
    +  'enableAssistiveMml',
    +  'enableMenu',
    +];
    +
    +/**
    + * Build the inline `window.MathJax = (...)` configuration script.
    + *
    + * Besides serializing the config, this wraps `startup.ready` so the a11y
    + * toggles in `mathjaxConfig.options` (most importantly `enableEnrichment`) are
    + * actually honored. MathJax 4's combined `tex-mml-chtml` component resets these
    + * flags to their defaults while augmenting the MathDocument at startup, so
    + * setting them in the config block alone has no effect — the only reliable
    + * place to apply them is on the live document *after* it is built. Disabling
    + * enrichment removes the speech-rule-engine work that otherwise dominates every
    + * typeset and makes formula-heavy previews slow to refresh
    + * (shd101wyy/vscode-markdown-preview-enhanced#2312).
    + */
    +export function buildMathJaxConfigScript(
    +  mathJaxConfig: Record<string, unknown>,
    +): string {
    +  return `window.MathJax = (${JSON.stringify(mathJaxConfig)});
    +(function () {
    +  var cfg = window.MathJax;
    +  cfg.startup = cfg.startup || {};
    +  // Capture any user-supplied ready hook now; MathJax replaces window.MathJax
    +  // with its live API during startup, so inside the hook we must reach for the
    +  // *current* window.MathJax.startup (which has defaultReady/document), not the
    +  // captured config object.
    +  var userReady = cfg.startup.ready;
    +  cfg.startup.ready = function () {
    +    var startup = window.MathJax.startup;
    +    if (typeof userReady === 'function') {
    +      userReady();
    +    } else {
    +      startup.defaultReady();
    +    }
    +    var doc = startup.document;
    +    var wanted =
    +      (window.MathJax.config && window.MathJax.config.options) || {};
    +    if (doc && doc.options) {
    +      var keys = ${JSON.stringify(A11Y_OPTION_KEYS)};
    +      for (var i = 0; i < keys.length; i++) {
    +        if (Object.prototype.hasOwnProperty.call(wanted, keys[i])) {
    +          doc.options[keys[i]] = wanted[keys[i]];
    +        }
    +      }
    +    }
    +  };
    +})();`;
    +}
    
  • src/markdown-engine/sanitize.ts+15 0 modified
    @@ -8,6 +8,7 @@
     
     import type { CheerioAPI } from 'cheerio';
     import type { AnyNode, Element } from 'domhandler';
    +import { normalizeWavedromSource } from '../renderers/wavedrom-source';
     
     const DANGEROUS_URL_PATTERN =
       /^\s*(javascript|vbscript)\s*:|^\s*data\s*:\s*text\/html/i;
    @@ -38,6 +39,20 @@ export function sanitizeRenderedHTML($: CheerioAPI): void {
         const scriptType = (el.attribs?.type || '').toLowerCase().trim();
         if (!SAFE_SCRIPT_TYPES.has(scriptType)) {
           $(el).remove();
    +      return;
    +    }
    +
    +    // WaveDrom data scripts are eval'd by the bundled WaveDrom renderer
    +    // (ProcessAll/eva) in presentation mode and HTML export. Normalize the
    +    // body to inert strict JSON so that eval can never execute attacker
    +    // controlled JavaScript (shd101wyy/vscode-markdown-preview-enhanced#2315).
    +    if (scriptType === 'wavedrom') {
    +      const safe = normalizeWavedromSource($(el).text());
    +      if (safe === null) {
    +        $(el).remove();
    +      } else {
    +        $(el).text(safe);
    +      }
         }
       });
     
    
  • src/notebook/types.ts+13 1 modified
    @@ -620,7 +620,19 @@ export function getDefaultMermaidConfig(): MermaidConfig {
     export function getDefaultMathjaxConfig(): JsonObject {
       return {
         tex: {},
    -    options: {},
    +    options: {
    +      // MathJax 4's combined `tex-mml-chtml` component bundles the a11y
    +      // speech-rule-engine and runs semantic *enrichment* (speech generation)
    +      // on every typeset. That enrichment is ~95% of MathJax 4's per-formula
    +      // cost and is the reason a preview with many formulas re-renders slowly
    +      // on every edit (shd101wyy/vscode-markdown-preview-enhanced#2312).
    +      // Disable it by default to restore MathJax-3-like typeset performance;
    +      // users who need screen-reader speech can set this back to `true` in
    +      // their `mathjaxConfig`. NOTE: MathJax ignores this flag when it is set
    +      // in the config block, so the engine re-applies it onto the live
    +      // MathDocument via a `startup.ready` hook (see markdown-engine).
    +      enableEnrichment: false,
    +    },
         loader: {},
       };
     }
    
  • src/renderers/bitfield.ts+2 2 modified
    @@ -1,12 +1,12 @@
     import { escape } from 'html-escaper';
    +import JSON5 from 'json5';
     import onml from 'onml';
     import { JsonObject } from 'type-fest';
     import render from 'bit-field/lib/render.js';
    -import { interpretJS } from '../utility';
     
     export async function renderBitfield(code: string, options: JsonObject) {
       try {
    -    const reg = interpretJS(code);
    +    const reg = JSON5.parse(code);
         const jsonml = render(reg, options);
         const html = onml.stringify(jsonml);
         return html;
    
  • src/renderers/wavedrom-source.ts+52 0 added
    @@ -0,0 +1,52 @@
    +import JSON5 from 'json5';
    +
    +/**
    + * Validate and normalize untrusted WaveDrom source.
    + *
    + * WaveDrom diagrams are embedded in the rendered HTML as
    + * `<script type="WaveDrom">...</script>` data containers. Historically the
    + * client evaluated this content with `eval("(" + source + ")")` (both in our
    + * own preview code and inside the bundled `WaveDrom.ProcessAll()` /
    + * `WaveDrom.eva()` helpers used for presentation mode and HTML export). Since
    + * the content comes straight from a user's markdown file, that allowed
    + * arbitrary JavaScript execution in the webview context
    + * (shd101wyy/vscode-markdown-preview-enhanced#2315).
    + *
    + * To neutralize every downstream consumer at once, we parse the source as
    + * JSON5 (WaveDrom's actual data syntax: unquoted keys, comments, trailing
    + * commas, single-quoted strings) and re-serialize it to *strict* JSON. After
    + * this, any later `eval`/`JSON.parse`/`ProcessAll` only ever sees inert data —
    + * a JSON object literal cannot execute code.
    + *
    + * The `<` escaping prevents a `</script>` substring inside a string value from
    + * breaking out of the surrounding `<script type="WaveDrom">` container (HTML
    + * does not interpret `<` inside a JSON string, but the browser would
    + * otherwise treat a literal `</script>` as the end of the script element).
    + *
    + * @returns the safe, strict-JSON string, or `null` if the source is not valid
    + * WaveDrom data (in which case callers should drop the diagram).
    + */
    +export function normalizeWavedromSource(raw: string): string | null {
    +  try {
    +    const data = JSON5.parse(raw);
    +    // WaveDrom roots are objects ({signal:[...]}, {reg:[...]}, {assign:[...]}).
    +    // Anything else (bare numbers/strings/null, or a top-level array) is not a
    +    // valid diagram.
    +    if (typeof data !== 'object' || data === null || Array.isArray(data)) {
    +      return null;
    +    }
    +    // Re-serialize to strict JSON. JSON5 accepts `Infinity`/`-Infinity`/`NaN`,
    +    // but `JSON.stringify` silently coerces them to `null`; throw instead so a
    +    // diagram relying on those values is dropped rather than rendered with
    +    // corrupted data.
    +    const json = JSON.stringify(data, (_key, value) => {
    +      if (typeof value === 'number' && !Number.isFinite(value)) {
    +        throw new SyntaxError('WaveDrom data contains a non-finite number');
    +      }
    +      return value;
    +    });
    +    return json.replace(/</g, '\\u003c');
    +  } catch {
    +    return null;
    +  }
    +}
    
  • src/tools/latex.ts+7 2 modified
    @@ -44,9 +44,14 @@ export function toSVGMarkdown(
       },
     ): Promise<string> {
       return new Promise<string>((resolve, reject) => {
    -    const task = spawn(latexEngine, [`"${texFilePath}"`], {
    +    // SECURITY: do NOT use `shell: true`. `latexEngine` comes from the
    +    // `latex_engine` code-chunk attribute (attacker-controlled markdown), so a
    +    // shell would let metacharacters chain extra commands. Spawning without a
    +    // shell runs only the named engine and passes the temp path as one literal
    +    // argument (the quotes that shell mode needed must be dropped). Code-chunk
    +    // execution is additionally gated behind `enableScriptExecution`.
    +    const task = spawn(latexEngine, [texFilePath], {
           cwd: path.dirname(texFilePath),
    -      shell: true,
         });
     
         const chunks: Buffer[] = [];
    
  • src/tools/pdf.ts+14 12 modified
    @@ -36,18 +36,20 @@ export function toSVGMarkdown(
     
         const svgFilePrefix = computeChecksum(pdfFilePath) + '_';
     
    -    const task = spawn(
    -      'pdf2svg',
    -      [
    -        `"${pdfFilePath}"`,
    -        `"${path.resolve(
    -          svgDirectoryPath ?? `/tmp/crossnote_pdf`,
    -          svgFilePrefix + '%d.svg',
    -        )}"`,
    -        'all',
    -      ],
    -      { shell: true },
    -    );
    +    // SECURITY: do NOT use `shell: true`. `pdfFilePath` can come from a
    +    // markdown `@import "…"` (auto-rendered on preview), so running through a
    +    // shell would let metacharacters in the path inject commands. Spawning
    +    // without a shell passes each path as a single literal argument (and the
    +    // surrounding quotes that shell mode required must be dropped, or they
    +    // become part of the filename).
    +    const task = spawn('pdf2svg', [
    +      pdfFilePath,
    +      path.resolve(
    +        svgDirectoryPath ?? `/tmp/crossnote_pdf`,
    +        svgFilePrefix + '%d.svg',
    +      ),
    +      'all',
    +    ]);
         const chunks: string[] = [];
         task.stdout.on('data', (chunk) => {
           chunks.push(chunk);
    
  • src/utility.ts+53 6 modified
    @@ -21,6 +21,46 @@ export function tempOpen(options: temp.AffixOptions): Promise<temp.OpenFile> {
       return temp.open(options);
     }
     
    +// Characters that are dangerous in a shell command line (the ImageMagick and
    +// mermaid converters build/spawn shell strings), invalid in Windows paths, or
    +// otherwise risky: shell metacharacters, quotes, whitespace, the backslash, and
    +// any Unicode control/format character (`\p{C}`, e.g. NUL, RTL override).
    +// Everything else — including Unicode letters such as CJK or accented Latin —
    +// is allowed, so non-English filenames keep working.
    +const UNSAFE_IMAGE_FILENAME_CHARS = /[\p{C}\s"'`<>:|?*\\$&;(){}[\]!^%~#]/u;
    +
    +/**
    + * Sanitize a user-supplied diagram `filename` attribute before it is used to
    + * build an output image path.
    + *
    + * The value comes from untrusted markdown (e.g. ```` ```mermaid {filename=…} ````)
    + * and is later joined into an output path that is handed to image converters
    + * which shell out — ImageMagick via `imagemagick-cli` (uses
    + * `child_process.exec`) and `@mermaid-js/mermaid-cli` (spawned with
    + * `shell: true`). Shell metacharacters in the name would therefore allow
    + * command injection on export. We reject names containing shell metacharacters,
    + * whitespace, control characters, or `..` traversal; anything unsafe returns
    + * `''` so the caller falls back to its auto-generated name. Unicode letters
    + * (CJK, accented Latin, …) are allowed — they are not shell-special.
    + *
    + * A leading `/` is permitted and kept: consistent with MPE's `imageFolderPath`
    + * convention, it means "relative to the project root" (resolved by the caller),
    + * NOT a filesystem-absolute path. The `..` rejection keeps it inside that root.
    + */
    +export function sanitizeImageFilename(name: string | undefined): string {
    +  if (!name) {
    +    return '';
    +  }
    +  if (UNSAFE_IMAGE_FILENAME_CHARS.test(name)) {
    +    return '';
    +  }
    +  // Refuse `..` segments so the resolved path can't escape its base directory.
    +  if (name.split('/').includes('..')) {
    +    return '';
    +  }
    +  return name;
    +}
    +
     /**
      * open html file in browser or open pdf file in reader ... etc
      * @param filePath
    @@ -31,13 +71,20 @@ export function openFile(filePath: string) {
           // C:\ like url.
           filePath = 'file:///' + filePath;
         }
    -    if (filePath.startsWith('file:///')) {
    -      return child_process.execFile('explorer.exe', [filePath]);
    -    } else {
    -      return child_process.exec(`start ${filePath}`);
    -    }
    +    // SECURITY: never pass `filePath` through a shell. `filePath` may be an
    +    // attacker-controlled href from a clicked preview link, so the previous
    +    // `child_process.exec('start ' + filePath)` ran via cmd.exe, where shell
    +    // metacharacters injected commands — e.g. a markdown link
    +    // `[x](mailto:a%26%20calc.exe)` decodes to `mailto:a& calc.exe` and the
    +    // `&` runs `calc.exe` as a second command (one-click RCE on Windows,
    +    // reported by @byte16384). `execFile` spawns without a shell, so `&`, `|`,
    +    // `&&`, … are passed verbatim as a single argument to `explorer.exe`,
    +    // which opens the file/URI via the OS default handler.
    +    return child_process.execFile('explorer.exe', [filePath]);
       } else if (process.platform === 'darwin') {
    -    child_process.execFile('open', [filePath]);
    +    // `--` stops option parsing so a `filePath` starting with `-` can't be
    +    // interpreted as a flag. `execFile` already avoids the shell.
    +    child_process.execFile('open', ['--', filePath]);
       } else {
         child_process.execFile('xdg-open', [filePath]);
       }
    
  • src/webview/containers/preview.ts+7 2 modified
    @@ -1,6 +1,7 @@
     import CryptoJS, { SHA256 } from 'crypto-js';
     import { escape } from 'html-escaper';
     import $ from 'jquery';
    +import JSON5 from 'json5';
     import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
     import { useContextMenu } from 'react-contexify';
     import { createContainer } from 'unstated-next';
    @@ -418,6 +419,10 @@ const PreviewContainer = createContainer(() => {
               return resolve();
             }
     
    +        // Clear MathJax's internal list of typeset items (it otherwise grows
    +        // unbounded across re-renders, leaking the detached nodes from the
    +        // freshly rebuilt hidden preview) and reset the equation numbering so
    +        // numbered equations don't drift on every edit.
             window['MathJax'].typesetClear(); // Don't pass element here!!!
             window['MathJax'].texReset();
             window['MathJax']
    @@ -466,11 +471,11 @@ const PreviewContainer = createContainer(() => {
             }
     
             try {
    -          const content = window.eval(`(${text})`);
    +          const content = JSON5.parse(text);
               window['WaveDrom'].RenderWaveForm(i, content, 'wavedrom');
               newWavedromCache[text] = el.innerHTML;
             } catch (error) {
    -          el.innerText = 'Failed to eval WaveDrom code. ' + error;
    +          el.innerText = 'Failed to render WaveDrom code. ' + error;
             }
           }
     
    
  • src/webview/lib/sanitize.ts+15 0 modified
    @@ -4,6 +4,7 @@
      */
     
     import DOMPurify from 'dompurify';
    +import { normalizeWavedromSource } from '../../renderers/wavedrom-source';
     
     // Script types used as data containers by diagram renderers (not executable)
     const SAFE_SCRIPT_TYPES = new Set(['wavedrom', 'text/tikz']);
    @@ -25,6 +26,20 @@ purify.addHook('uponSanitizeElement', (node, data) => {
         const scriptType = (el.getAttribute?.('type') || '').toLowerCase().trim();
         if (!SAFE_SCRIPT_TYPES.has(scriptType)) {
           el.parentNode?.removeChild(el);
    +      return;
    +    }
    +
    +    // WaveDrom data scripts are eval'd by the bundled WaveDrom renderer in
    +    // presentation mode. Normalize the body to inert strict JSON so eval can
    +    // never execute attacker controlled JavaScript
    +    // (shd101wyy/vscode-markdown-preview-enhanced#2315).
    +    if (scriptType === 'wavedrom') {
    +      const safe = normalizeWavedromSource(el.textContent || '');
    +      if (safe === null) {
    +        el.parentNode?.removeChild(el);
    +      } else {
    +        el.textContent = safe;
    +      }
         }
       }
     });
    
  • test/bitfield.test.ts+64 0 modified
    @@ -22,3 +22,67 @@ describe('Bitfield renderer', () => {
         expect(result).toContain('<pre class="language-text">');
       });
     });
    +
    +describe('Bitfield parser security', () => {
    +  it('parses bitfield with unquoted keys', async () => {
    +    const code = `[
    +      { name: "IPO", bits: 8, attr: "RO" },
    +      { bits: 7 }
    +    ]`;
    +    const result = await renderBitfield(code, {});
    +    expect(typeof result).toBe('string');
    +    expect(result).toContain('<svg');
    +  });
    +
    +  it('parses bitfield with single-quoted strings', async () => {
    +    const code = `[
    +      { name: 'IPO', bits: 8, attr: 'RO' }
    +    ]`;
    +    const result = await renderBitfield(code, {});
    +    expect(typeof result).toBe('string');
    +    expect(result).toContain('<svg');
    +  });
    +
    +  it('parses bitfield with trailing commas', async () => {
    +    const code = `[
    +      { name: "IPO", bits: 8, attr: "RO", },
    +      { name: "BRK", bits: 5, attr: "RW", },
    +      { bits: 7, },
    +    ]`;
    +    const result = await renderBitfield(code, {});
    +    expect(typeof result).toBe('string');
    +    expect(result).toContain('<svg');
    +  });
    +
    +  it('parses bitfield with // comments', async () => {
    +    const code = `[
    +      // interrupt pending register
    +      { name: "IPO", bits: 8, attr: "RO" },
    +      { bits: 7 }
    +    ]`;
    +    const result = await renderBitfield(code, {});
    +    expect(typeof result).toBe('string');
    +    expect(result).toContain('<svg');
    +  });
    +
    +  it('parses bitfield with hex numbers', async () => {
    +    const code = `[
    +      { name: "STATUS", bits: 8, addr: 0x0F }
    +    ]`;
    +    const result = await renderBitfield(code, {});
    +    expect(typeof result).toBe('string');
    +    expect(result).toContain('<svg');
    +  });
    +
    +  it('blocks code execution via function call', async () => {
    +    const code = '(() => { throw new Error("pwned"); })()';
    +    const result = await renderBitfield(code, {});
    +    expect(result).toContain('<pre class="language-text">');
    +  });
    +
    +  it('blocks code execution via constructor access', async () => {
    +    const code = 'this.constructor.constructor("return process")()';
    +    const result = await renderBitfield(code, {});
    +    expect(result).toContain('<pre class="language-text">');
    +  });
    +});
    
  • test/browser/mathjax.spec.ts+183 0 added
    @@ -0,0 +1,183 @@
    +import { expect, Page, test } from '@playwright/test';
    +import { buildMathJaxConfigScript } from '../../src/markdown-engine/mathjax-config';
    +import { getDefaultMathjaxConfig } from '../../src/notebook/types';
    +import { startServer, TestServer } from './server';
    +
    +/**
    + * Real-browser tests for the client-side MathJax pipeline.
    + *
    + *  - Equation numbering must stay correct across re-renders. The preview
    + *    rebuilds the hidden DOM and re-typesets on every edit; without
    + *    `typesetClear()` + `texReset()` MathJax keeps the previous run's labels
    + *    and emits "Label … multiply defined" errors with drifting numbers.
    + *  - Semantic enrichment (speech-rule-engine) must be disabled by default for
    + *    performance (#2312), and re-enableable via `mathjaxConfig`.
    + */
    +
    +// Minimal shape of the MathJax global used inside page.evaluate callbacks.
    +interface MathJaxGlobal {
    +  typesetClear: () => void;
    +  texReset: () => void;
    +  typesetPromise: (elements: Element[]) => Promise<void>;
    +  startup: {
    +    promise: Promise<void>;
    +    document: { options: Record<string, unknown> };
    +  };
    +}
    +
    +type WindowWithMathJax = Window &
    +  typeof globalThis & { MathJax: MathJaxGlobal };
    +
    +let server: TestServer;
    +
    +test.beforeAll(async () => {
    +  server = await startServer();
    +});
    +
    +test.afterAll(async () => {
    +  await server?.close();
    +});
    +
    +const NUMBERED_DOC =
    +  '<p>$$\\begin{equation}\\label{eq:one}a+b=c\\end{equation}$$</p>' +
    +  '<p>$$\\begin{equation}\\label{eq:two}d+e=f\\end{equation}$$</p>';
    +
    +function makeConfig(optionOverrides?: Record<string, unknown>) {
    +  const cfg = getDefaultMathjaxConfig() as Record<string, unknown>;
    +  cfg.tex = {
    +    inlineMath: [['$', '$']],
    +    displayMath: [['$$', '$$']],
    +    tags: 'ams',
    +  };
    +  cfg.startup = { typeset: false };
    +  if (optionOverrides) {
    +    cfg.options = {
    +      ...((cfg.options as Record<string, unknown>) || {}),
    +      ...optionOverrides,
    +    };
    +  }
    +  return cfg;
    +}
    +
    +/**
    + * Load a fresh MathJax instance into the page using the engine's real
    + * `buildMathJaxConfigScript` output, then wait for startup to finish.
    + */
    +async function loadMathJax(page: Page, config: Record<string, unknown>) {
    +  await page.goto(server.url);
    +  page.on('pageerror', (e) => {
    +    throw e;
    +  });
    +  await page.addScriptTag({ content: buildMathJaxConfigScript(config) });
    +  await page.addScriptTag({ url: `${server.url}/mathjax/tex-mml-chtml.js` });
    +  await page.evaluate(async () => {
    +    await (window as WindowWithMathJax).MathJax.startup.promise;
    +  });
    +}
    +
    +/** Render the doc `rounds` times, mirroring the preview's renderMathJax. */
    +async function renderRounds(
    +  page: Page,
    +  html: string,
    +  withReset: boolean,
    +  rounds: number = 3,
    +) {
    +  return page.evaluate(
    +    async ({ html, withReset, rounds }) => {
    +      const MathJax = (window as WindowWithMathJax).MathJax;
    +      const hidden = document.getElementById('hidden')!;
    +      const results: { tags: string[]; errors: string[] }[] = [];
    +      for (let r = 0; r < rounds; r++) {
    +        hidden.innerHTML = html;
    +        if (withReset) {
    +          MathJax.typesetClear();
    +          MathJax.texReset();
    +        }
    +        await MathJax.typesetPromise([hidden]);
    +        // CHTML renders each equation's number inside an <mjx-labels> element,
    +        // e.g. "(1)".
    +        const tags = [...hidden.querySelectorAll('mjx-labels')]
    +          .map((n) => (n.textContent || '').trim())
    +          .filter((t) => /^\(\d+\)$/.test(t));
    +        const errors = [...hidden.querySelectorAll('mjx-merror')].map(
    +          (n) => n.getAttribute('data-mjx-error') || n.textContent || '',
    +        );
    +        results.push({ tags, errors });
    +        hidden.innerHTML = '';
    +      }
    +      return results;
    +    },
    +    { html, withReset, rounds },
    +  );
    +}
    +
    +test('equation numbering is stable across re-renders (with typesetClear/texReset)', async ({
    +  page,
    +}) => {
    +  await loadMathJax(page, makeConfig());
    +  const rounds = await renderRounds(page, NUMBERED_DOC, true);
    +
    +  for (const [i, round] of rounds.entries()) {
    +    expect(round.errors, `render #${i} should have no MathJax errors`).toEqual(
    +      [],
    +    );
    +    // Two numbered equations → tags (1) and (2), reset to the same values
    +    // on every render.
    +    expect(round.tags, `render #${i} equation numbers`).toEqual(['(1)', '(2)']);
    +  }
    +});
    +
    +test('dropping typesetClear/texReset regresses numbering (guards why we keep them)', async ({
    +  page,
    +}) => {
    +  await loadMathJax(page, makeConfig());
    +  const rounds = await renderRounds(page, NUMBERED_DOC, false);
    +
    +  // First render is clean; the regression shows up once the same labels are
    +  // typeset again without resetting MathJax's label/equation state.
    +  const laterErrors = rounds.slice(1).flatMap((r) => r.errors);
    +  expect(laterErrors.join('\n')).toMatch(/multiply defined/i);
    +});
    +
    +test('semantic enrichment is disabled by default for performance (#2312)', async ({
    +  page,
    +}) => {
    +  await loadMathJax(page, makeConfig());
    +  await renderRounds(page, NUMBERED_DOC, true, 1);
    +
    +  const state = await page.evaluate(() => {
    +    const MathJax = (window as WindowWithMathJax).MathJax;
    +    const hidden = document.getElementById('hidden')!;
    +    // Re-render so we can inspect the output DOM for enrichment artifacts.
    +    hidden.innerHTML = '<p>$$x^2 + y^2 = z^2$$</p>';
    +    return MathJax.typesetPromise([hidden]).then(() => ({
    +      enableEnrichment: MathJax.startup.document.options.enableEnrichment,
    +      semanticNodes: hidden.querySelectorAll(
    +        '[data-semantic-id], [data-semantic-speech], mjx-assistive-mml',
    +      ).length,
    +    }));
    +  });
    +
    +  expect(state.enableEnrichment).toBe(false);
    +  // Enrichment off → no semantic tree / assistive MathML generated.
    +  expect(state.semanticNodes).toBe(0);
    +});
    +
    +test('semantic enrichment can be re-enabled via mathjaxConfig', async ({
    +  page,
    +}) => {
    +  await loadMathJax(page, makeConfig({ enableEnrichment: true }));
    +
    +  const enableEnrichment = await page.evaluate(() => {
    +    const MathJax = (window as WindowWithMathJax).MathJax;
    +    const hidden = document.getElementById('hidden')!;
    +    hidden.innerHTML = '<p>$$x^2 + y^2 = z^2$$</p>';
    +    return MathJax.typesetPromise([hidden]).then(
    +      () => MathJax.startup.document.options.enableEnrichment,
    +    );
    +  });
    +
    +  // The startup.ready hook must copy the user's override onto the live
    +  // document (MathJax ignores it in the config block).
    +  expect(enableEnrichment).toBe(true);
    +});
    
  • test/browser/server.ts+91 0 added
    @@ -0,0 +1,91 @@
    +import * as fs from 'fs';
    +import * as http from 'http';
    +import * as path from 'path';
    +
    +const MATHJAX_DIR = path.resolve(__dirname, '../../node_modules/mathjax');
    +const WAVEDROM_DIR = path.resolve(__dirname, '../../dependencies/wavedrom');
    +
    +const CONTENT_TYPES: Record<string, string> = {
    +  '.js': 'text/javascript; charset=utf-8',
    +  '.mjs': 'text/javascript; charset=utf-8',
    +  '.cjs': 'text/javascript; charset=utf-8',
    +  '.json': 'application/json; charset=utf-8',
    +  '.css': 'text/css; charset=utf-8',
    +  '.wasm': 'application/wasm',
    +  '.woff': 'font/woff',
    +  '.woff2': 'font/woff2',
    +  '.html': 'text/html; charset=utf-8',
    +};
    +
    +const PAGE = `<!DOCTYPE html>
    +<html>
    +  <head><meta charset="utf-8"></head>
    +  <body><div id="hidden" class="hidden-preview"></div></body>
    +</html>`;
    +
    +export interface TestServer {
    +  url: string;
    +  close(): Promise<void>;
    +}
    +
    +/**
    + * Serve a blank preview page at `/` and the locally installed MathJax 4
    + * package under `/mathjax/...` over real HTTP (so the speech-rule-engine's
    + * web worker, which won't run from a `file://` origin, works as it does in the
    + * actual webview).
    + */
    +// URL prefix → on-disk root. Static assets are served from these so MathJax's
    +// component loader and WaveDrom's skins resolve their siblings over real HTTP.
    +const STATIC_MOUNTS: { prefix: string; root: string }[] = [
    +  { prefix: '/mathjax/', root: MATHJAX_DIR },
    +  { prefix: '/wavedrom/', root: WAVEDROM_DIR },
    +];
    +
    +export async function startServer(): Promise<TestServer> {
    +  const server = http.createServer((req, res) => {
    +    const url = (req.url || '/').split('?')[0];
    +    if (url === '/' || url === '/index.html') {
    +      res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
    +      res.end(PAGE);
    +      return;
    +    }
    +    const mount = STATIC_MOUNTS.find((m) => url.startsWith(m.prefix));
    +    if (mount) {
    +      const rel = decodeURIComponent(url.slice(mount.prefix.length));
    +      // Resolve within the mount root and refuse path traversal.
    +      const filePath = path.resolve(mount.root, rel);
    +      if (!filePath.startsWith(mount.root)) {
    +        res.writeHead(403);
    +        res.end('forbidden');
    +        return;
    +      }
    +      fs.readFile(filePath, (err, data) => {
    +        if (err) {
    +          res.writeHead(404);
    +          res.end('not found');
    +          return;
    +        }
    +        const type =
    +          CONTENT_TYPES[path.extname(filePath)] || 'application/octet-stream';
    +        res.writeHead(200, { 'content-type': type });
    +        res.end(data);
    +      });
    +      return;
    +    }
    +    res.writeHead(404);
    +    res.end('not found');
    +  });
    +
    +  await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
    +  const address = server.address();
    +  if (!address || typeof address === 'string') {
    +    throw new Error('failed to bind test server');
    +  }
    +  return {
    +    url: `http://127.0.0.1:${address.port}`,
    +    close: () =>
    +      new Promise<void>((resolve, reject) =>
    +        server.close((err) => (err ? reject(err) : resolve())),
    +      ),
    +  };
    +}
    
  • test/browser/wavedrom.spec.ts+108 0 added
    @@ -0,0 +1,108 @@
    +import { expect, Page, test } from '@playwright/test';
    +import * as cheerio from 'cheerio';
    +import { sanitizeRenderedHTML } from '../../src/markdown-engine/sanitize';
    +import { startServer, TestServer } from './server';
    +
    +/**
    + * Real-browser tests for WaveDrom rendering and the eval-based code-execution
    + * fix (shd101wyy/vscode-markdown-preview-enhanced#2315).
    + *
    + * The bundled WaveDrom renderer (used in presentation mode and HTML export)
    + * runs `WaveDrom.ProcessAll()`, which evaluates the body of every
    + * `<script type="WaveDrom">` with `eval("(" + innerHTML + ")")`. Our HTML
    + * sanitizer defangs this by validating + normalizing that body to inert strict
    + * JSON (and dropping it entirely if it isn't valid data), so `eval` can never
    + * execute attacker-controlled JavaScript. These tests exercise that exact
    + * runtime path in Chromium.
    + */
    +
    +interface WaveDromGlobal {
    +  ProcessAll: () => void;
    +}
    +type WindowWithWaveDrom = Window &
    +  typeof globalThis & { WaveDrom: WaveDromGlobal; __pwned?: boolean };
    +
    +let server: TestServer;
    +
    +test.beforeAll(async () => {
    +  server = await startServer();
    +});
    +
    +test.afterAll(async () => {
    +  await server?.close();
    +});
    +
    +/** Run our real server-side sanitizer over a body HTML fragment. */
    +function sanitize(html: string): string {
    +  const $ = cheerio.load(html);
    +  sanitizeRenderedHTML($);
    +  return $('body').html() ?? '';
    +}
    +
    +/**
    + * Load the given body HTML into the page, pull in the vendored WaveDrom
    + * scripts (same order the engine emits), and run `WaveDrom.ProcessAll()` —
    + * mirroring the presentation/export render path. Returns whether an SVG was
    + * produced and whether the `__pwned` execution sentinel was tripped.
    + */
    +async function processAll(page: Page, bodyHtml: string) {
    +  await page.goto(server.url);
    +  await page.evaluate((html) => {
    +    (window as WindowWithWaveDrom).__pwned = false;
    +    document.getElementById('hidden')!.innerHTML = html;
    +  }, bodyHtml);
    +  // Load order matches src/markdown-engine/index.ts: skins, then the library.
    +  await page.addScriptTag({ url: `${server.url}/wavedrom/skins/default.js` });
    +  await page.addScriptTag({ url: `${server.url}/wavedrom/skins/narrow.js` });
    +  await page.addScriptTag({ url: `${server.url}/wavedrom/wavedrom.min.js` });
    +  return page.evaluate(() => {
    +    (window as WindowWithWaveDrom).WaveDrom.ProcessAll();
    +    const hidden = document.getElementById('hidden')!;
    +    return {
    +      pwned: (window as WindowWithWaveDrom).__pwned === true,
    +      svgCount: hidden.querySelectorAll('svg').length,
    +      hasWavedromScript: hidden.querySelectorAll('script[type="WaveDrom" i]')
    +        .length,
    +    };
    +  });
    +}
    +
    +const MALICIOUS =
    +  '<div class="wavedrom"><script type="WaveDrom">' +
    +  '(function(){ window.__pwned = true; return { signal: [] }; })()' +
    +  '</script></div>';
    +
    +const BENIGN_JSON5 =
    +  '<div class="wavedrom"><script type="WaveDrom">' +
    +  "{ signal: [ { name: 'clk', wave: 'p...' }, { name: 'dat', wave: 'x.34' } ] }" +
    +  '</script></div>';
    +
    +test('UNSANITIZED malicious WaveDrom executes via ProcessAll (demonstrates the vuln)', async ({
    +  page,
    +}) => {
    +  // This is the pre-fix behavior: ProcessAll's eval runs attacker JS. It
    +  // guards *why* the sanitizer normalization below is necessary.
    +  const result = await processAll(page, MALICIOUS);
    +  expect(result.pwned).toBe(true);
    +});
    +
    +test('SANITIZED malicious WaveDrom cannot execute (#2315 fix)', async ({
    +  page,
    +}) => {
    +  // The IIFE is not valid WaveDrom data, so the sanitizer drops the script.
    +  const safe = sanitize(MALICIOUS);
    +  expect(safe).not.toContain('__pwned');
    +  const result = await processAll(page, safe);
    +  expect(result.pwned).toBe(false);
    +  expect(result.hasWavedromScript).toBe(0);
    +});
    +
    +test('SANITIZED benign WaveDrom still renders an SVG', async ({ page }) => {
    +  // JSON5 (unquoted keys, single quotes) is normalized to strict JSON and
    +  // then rendered by ProcessAll's eval — which only ever sees inert data.
    +  const safe = sanitize(BENIGN_JSON5);
    +  expect(safe).toContain('"signal"');
    +  const result = await processAll(page, safe);
    +  expect(result.pwned).toBe(false);
    +  expect(result.svgCount).toBeGreaterThan(0);
    +});
    
  • test/command-injection.test.ts+157 0 added
    @@ -0,0 +1,157 @@
    +/**
    + * Regression tests for Windows command injection via clicked preview links
    + * and diagram output filenames (reported by @byte16384).
    + *
    + * A crafted markdown link such as
    + *   [x](mailto:hello@byte256.csrf.blog%26%20calc.exe)
    + * decodes to `mailto:hello@byte256.csrf.blog& calc.exe` and used to reach
    + * `child_process.exec('start ' + href)`, where cmd.exe interpreted `&` as a
    + * command separator — one-click RCE on Windows. `openFile` must never use a
    + * shell. Likewise the diagram `filename` attribute flows into image converters
    + * that shell out, so it must be sanitized.
    + */
    +import * as child_process from 'child_process';
    +import { openFile, sanitizeImageFilename } from '../src/utility';
    +
    +jest.mock('child_process', () => ({
    +  execFile: jest.fn(),
    +  exec: jest.fn(),
    +}));
    +
    +const execFileMock = child_process.execFile as unknown as jest.Mock;
    +const execMock = child_process.exec as unknown as jest.Mock;
    +
    +function withPlatform(platform: NodeJS.Platform, fn: () => void) {
    +  const original = Object.getOwnPropertyDescriptor(process, 'platform');
    +  Object.defineProperty(process, 'platform', {
    +    value: platform,
    +    configurable: true,
    +  });
    +  try {
    +    fn();
    +  } finally {
    +    if (original) {
    +      Object.defineProperty(process, 'platform', original);
    +    }
    +  }
    +}
    +
    +describe('openFile never uses a shell (#byte16384 Windows RCE)', () => {
    +  beforeEach(() => {
    +    execFileMock.mockReset();
    +    execMock.mockReset();
    +  });
    +
    +  it('does not call child_process.exec on Windows', () => {
    +    withPlatform('win32', () => {
    +      openFile('mailto:hello@byte256.csrf.blog& calc.exe');
    +    });
    +    expect(execMock).not.toHaveBeenCalled();
    +    expect(execFileMock).toHaveBeenCalledTimes(1);
    +  });
    +
    +  it('passes a malicious href as a single, unsplit argument to explorer.exe', () => {
    +    withPlatform('win32', () => {
    +      openFile('mailto:hello@byte256.csrf.blog& calc.exe');
    +    });
    +    const [command, args] = execFileMock.mock.calls[0];
    +    expect(command).toBe('explorer.exe');
    +    // The whole string is one argument — no shell, so `&` cannot split a
    +    // second command.
    +    expect(args).toEqual(['mailto:hello@byte256.csrf.blog& calc.exe']);
    +  });
    +
    +  it('keeps other shell metacharacters inside one argument', () => {
    +    withPlatform('win32', () => {
    +      openFile('http://x/?a=1 && calc.exe | whoami');
    +    });
    +    const [, args] = execFileMock.mock.calls[0];
    +    expect(args).toHaveLength(1);
    +    expect(args[0]).toBe('http://x/?a=1 && calc.exe | whoami');
    +  });
    +
    +  it('normalizes a drive path to a file:// URI and opens via explorer.exe', () => {
    +    withPlatform('win32', () => {
    +      openFile('C:\\Users\\me\\report.pdf');
    +    });
    +    expect(execFileMock).toHaveBeenCalledWith('explorer.exe', [
    +      'file:///C:\\Users\\me\\report.pdf',
    +    ]);
    +  });
    +
    +  it('uses `open --` on macOS so a leading-dash arg is not a flag', () => {
    +    withPlatform('darwin', () => {
    +      openFile('-x');
    +    });
    +    expect(execMock).not.toHaveBeenCalled();
    +    expect(execFileMock).toHaveBeenCalledWith('open', ['--', '-x']);
    +  });
    +
    +  it('uses xdg-open (no shell) on Linux', () => {
    +    withPlatform('linux', () => {
    +      openFile('mailto:a& calc');
    +    });
    +    expect(execMock).not.toHaveBeenCalled();
    +    expect(execFileMock).toHaveBeenCalledWith('xdg-open', ['mailto:a& calc']);
    +  });
    +});
    +
    +describe('sanitizeImageFilename (diagram export filename injection)', () => {
    +  it('accepts plain file names', () => {
    +    expect(sanitizeImageFilename('diagram.png')).toBe('diagram.png');
    +    expect(sanitizeImageFilename('my-chart_v2.png')).toBe('my-chart_v2.png');
    +  });
    +
    +  it('accepts a subdirectory path', () => {
    +    expect(sanitizeImageFilename('assets/diagram.png')).toBe(
    +      'assets/diagram.png',
    +    );
    +  });
    +
    +  it('accepts non-ASCII (Unicode) filenames', () => {
    +    // Unicode letters have no shell meaning; non-English filenames must work.
    +    expect(sanitizeImageFilename('图表.png')).toBe('图表.png');
    +    expect(sanitizeImageFilename('schéma_électrique.png')).toBe(
    +      'schéma_électrique.png',
    +    );
    +    expect(sanitizeImageFilename('диаграмма.png')).toBe('диаграмма.png');
    +    expect(sanitizeImageFilename('assets/図.png')).toBe('assets/図.png');
    +  });
    +
    +  it('accepts a leading-slash project-root path (MPE convention, not absolute)', () => {
    +    // `/assets/x.png` means "relative to the project root" — the caller
    +    // resolves it against projectDirectoryPath, not the filesystem root.
    +    expect(sanitizeImageFilename('/assets/diagram.png')).toBe(
    +      '/assets/diagram.png',
    +    );
    +  });
    +
    +  it('rejects shell metacharacters', () => {
    +    expect(sanitizeImageFilename('x.png && calc.exe')).toBe('');
    +    expect(sanitizeImageFilename('x.png; rm -rf /')).toBe('');
    +    expect(sanitizeImageFilename('$(calc).png')).toBe('');
    +    expect(sanitizeImageFilename('`calc`.png')).toBe('');
    +    expect(sanitizeImageFilename('a|b.png')).toBe('');
    +    expect(sanitizeImageFilename('"quoted".png')).toBe('');
    +  });
    +
    +  it('rejects whitespace and control characters', () => {
    +    expect(sanitizeImageFilename('my diagram.png')).toBe('');
    +    expect(sanitizeImageFilename('a\tb.png')).toBe('');
    +    expect(sanitizeImageFilename('a\nb.png')).toBe('');
    +    expect(sanitizeImageFilename('a\x00b.png')).toBe('');
    +    // Unicode RTL override (filename-spoofing / control) is rejected.
    +    expect(sanitizeImageFilename('evil‮gnp.png')).toBe('');
    +  });
    +
    +  it('rejects `..` path traversal (even with a leading slash)', () => {
    +    expect(sanitizeImageFilename('../../etc/passwd')).toBe('');
    +    expect(sanitizeImageFilename('a/../../b.png')).toBe('');
    +    expect(sanitizeImageFilename('/../outside.png')).toBe('');
    +  });
    +
    +  it('returns empty for empty/undefined input (caller falls back to default)', () => {
    +    expect(sanitizeImageFilename(undefined)).toBe('');
    +    expect(sanitizeImageFilename('')).toBe('');
    +  });
    +});
    
  • test/math.test.ts+56 0 modified
    @@ -11,7 +11,9 @@
      * renderer's output.
      */
     import * as path from 'path';
    +import { buildMathJaxConfigScript } from '../src/markdown-engine/mathjax-config';
     import { Notebook } from '../src/notebook/index';
    +import { getDefaultMathjaxConfig } from '../src/notebook/types';
     
     describe('Math rendering', () => {
       let notebook: Notebook;
    @@ -374,3 +376,57 @@ describe('Math rendering with custom delimiters', () => {
         expect(html).not.toContain('class="katex"');
       });
     });
    +
    +describe('MathJax config defaults', () => {
    +  it('disables a11y semantic enrichment for performance (#2312)', () => {
    +    // Enrichment (speech-rule-engine) is ~95% of MathJax 4's per-formula
    +    // typeset cost; disabling it restores MathJax-3-like preview performance.
    +    const config = getDefaultMathjaxConfig();
    +    const options = config.options as Record<string, unknown>;
    +    expect(options.enableEnrichment).toBe(false);
    +  });
    +
    +  it('preserves tex and loader config sections', () => {
    +    const config = getDefaultMathjaxConfig();
    +    expect(config.tex).toEqual({});
    +    expect(config.loader).toEqual({});
    +  });
    +
    +  it('is a pure object (no shared mutable references)', () => {
    +    const a = getDefaultMathjaxConfig();
    +    const b = getDefaultMathjaxConfig();
    +    expect(a).not.toBe(b);
    +    expect(a).toEqual(b);
    +  });
    +});
    +
    +describe('buildMathJaxConfigScript (#2312 enrichment override)', () => {
    +  it('serializes the config onto window.MathJax', () => {
    +    const script = buildMathJaxConfigScript(getDefaultMathjaxConfig());
    +    expect(script).toContain('window.MathJax = (');
    +    expect(script).toContain('"enableEnrichment":false');
    +  });
    +
    +  it('wraps startup.ready to re-apply a11y toggles onto the live document', () => {
    +    const script = buildMathJaxConfigScript(getDefaultMathjaxConfig());
    +    // The ready hook must run the default startup and then copy the
    +    // configured a11y options onto the built MathDocument (where they
    +    // actually take effect — MathJax ignores them in the config block).
    +    expect(script).toContain('cfg.startup.ready = function');
    +    expect(script).toContain('defaultReady()');
    +    expect(script).toContain('doc.options[keys[i]] = wanted[keys[i]]');
    +    expect(script).toContain('enableEnrichment');
    +  });
    +
    +  it('preserves a user-provided ready hook', () => {
    +    const script = buildMathJaxConfigScript({ options: {} });
    +    expect(script).toContain("typeof userReady === 'function'");
    +    expect(script).toContain('userReady()');
    +  });
    +
    +  it('produces a syntactically valid script', () => {
    +    const script = buildMathJaxConfigScript(getDefaultMathjaxConfig());
    +    // Wrap so the bare `window.MathJax = (...)` assignment parses.
    +    expect(() => new Function('window', script)).not.toThrow();
    +  });
    +});
    
  • test/sanitize.test.ts+39 0 modified
    @@ -138,6 +138,45 @@ describe('sanitizeRenderedHTML (CVE-2025-65716)', () => {
           expect(result).toContain('{"signal":[]}');
         });
     
    +    it('normalizes JSON5 WaveDrom data scripts to strict JSON', () => {
    +      const result = sanitize(
    +        `<div class="wavedrom"><script type="WaveDrom">{ signal: [ { name: 'clk', wave: 'p..' }, ], }</script></div>`,
    +      );
    +      expect(result).toContain('<script type="WaveDrom">');
    +      // unquoted keys / single quotes / trailing commas become strict JSON
    +      expect(result).toContain('{"signal":[{"name":"clk","wave":"p.."}]}');
    +      expect(result).not.toContain("'clk'");
    +    });
    +
    +    it('drops WaveDrom data scripts that contain executable code', () => {
    +      const result = sanitize(
    +        `<div class="wavedrom"><script type="WaveDrom">(()=>{return globalThis.process})()</script></div>`,
    +      );
    +      expect(result).not.toContain('<script');
    +      expect(result).not.toContain('globalThis');
    +    });
    +
    +    it('drops WaveDrom data scripts with a function-call payload', () => {
    +      const result = sanitize(
    +        `<div class="wavedrom"><script type="WaveDrom">alert(1)</script></div>`,
    +      );
    +      expect(result).not.toContain('<script');
    +      expect(result).not.toContain('alert(1)');
    +    });
    +
    +    it('escapes a </script> value so it cannot break out after re-serialization', () => {
    +      // The raw input uses a JSON escape (<\/script>) so the HTML parser does
    +      // NOT treat it as a closing tag; JSON5 decodes it to a literal
    +      // "</script>" string value, which JSON.stringify would otherwise emit
    +      // raw and break out of the <script> container.
    +      const result = sanitize(
    +        '<div class="wavedrom"><script type="WaveDrom">{"name":"<\\/script><img src=x onerror=alert(1)>"}</script></div>',
    +      );
    +      expect(result).toContain('<script type="WaveDrom">');
    +      expect(result).not.toContain('</script><img');
    +      expect(result).toContain('\\u003c/script>');
    +    });
    +
         it('preserves TikZ scripts', () => {
           const tikzCode =
             '\\begin{tikzpicture}\\draw (0,0) -- (1,1);\\end{tikzpicture}';
    
  • test/wavedrom-parser.test.ts+150 0 added
    @@ -0,0 +1,150 @@
    +import JSON5 from 'json5';
    +
    +describe('WaveDrom parser security (CVE-2026-wavedrom-eval)', () => {
    +  describe('JSON5.parse correctly handles WaveDrom input', () => {
    +    test('parses standard JSON (double-quoted keys)', () => {
    +      const result = JSON5.parse(
    +        '{"signal": [{"name": "clk", "wave": "p......"}]}',
    +      );
    +      expect(result).toEqual({
    +        signal: [{ name: 'clk', wave: 'p......' }],
    +      });
    +    });
    +
    +    test('parses WaveDrom with unquoted keys', () => {
    +      const result = JSON5.parse(`{ signal : [
    +  { name: "clk",  wave: "p......" },
    +  { name: "bus",  wave: "x.34.5x",   data: "head body tail" },
    +  { name: "wire", wave: "0.1..0." },
    +]}`);
    +      expect(result.signal).toHaveLength(3);
    +      expect(result.signal[0].name).toBe('clk');
    +    });
    +
    +    test('parses WaveDrom with single-quoted strings', () => {
    +      const result = JSON5.parse(`{
    +  signal: [
    +    { name: 'clk', wave: 'p......' },
    +  ]
    +}`);
    +      expect(result.signal[0].name).toBe('clk');
    +    });
    +
    +    test('parses WaveDrom with // comments', () => {
    +      const result = JSON5.parse(`{
    +  signal: [
    +    // clock signal
    +    { name: "clk", wave: "p......" },
    +    // data bus
    +    { name: "bus", wave: "x.34.5x", data: "head body tail" },
    +  ]
    +}`);
    +      expect(result.signal).toHaveLength(2);
    +      expect(result.signal[0].name).toBe('clk');
    +    });
    +
    +    test('parses WaveDrom with /* */ comments', () => {
    +      const result = JSON5.parse(`{
    +  signal: [
    +    /* main clock */
    +    { name: "clk", wave: "p......" },
    +  ]
    +}`);
    +      expect(result.signal[0].name).toBe('clk');
    +    });
    +
    +    test('parses WaveDrom with trailing commas', () => {
    +      const result = JSON5.parse(`{
    +  signal: [
    +    { name: "clk", wave: "p......", },
    +  ],
    +}`);
    +      expect(result.signal[0].name).toBe('clk');
    +    });
    +
    +    test('parses WaveDrom with hex numbers', () => {
    +      const result = JSON5.parse('{ addr: 0xDEAD }');
    +      expect(result.addr).toBe(0xdead);
    +    });
    +
    +    test('parses WaveDrom with Infinity and NaN', () => {
    +      const result = JSON5.parse(
    +        '{ max: Infinity, min: -Infinity, value: NaN }',
    +      );
    +      expect(result.max).toBe(Infinity);
    +      expect(result.min).toBe(-Infinity);
    +      expect(isNaN(result.value)).toBe(true);
    +    });
    +
    +    test('parses multiline WaveDrom input', () => {
    +      const result = JSON5.parse(`{
    +  signal: [
    +    { name: "clk",     wave: "p.....|..." },
    +    { name: "data",    wave: "x.345x|=.x", data: ["head", "body", "tail", "data"] },
    +    { name: "req",     wave: "0.1..0|1.0" },
    +    {},
    +    { name: "ack",     wave: "1.....|01." },
    +  ],
    +  head: { text: "WaveDrom example", tick: 0 },
    +  foot: { text: "Figure 1", tock: 9 },
    +}`);
    +      expect(result.signal).toHaveLength(5);
    +      expect(result.head.text).toBe('WaveDrom example');
    +    });
    +  });
    +
    +  describe('JSON5.parse blocks code execution', () => {
    +    test('throws on function calls', () => {
    +      expect(() => JSON5.parse('alert("xss")')).toThrow();
    +    });
    +
    +    test('throws on function expressions', () => {
    +      expect(() => JSON5.parse('(function() { alert("xss") })()')).toThrow();
    +    });
    +
    +    test('throws on variable assignments', () => {
    +      expect(() => JSON5.parse('a = 1')).toThrow();
    +    });
    +
    +    test('throws on arbitrary JavaScript payloads', () => {
    +      const exploitPayload = `
    +        (() => {
    +          const vscodeApi = { postMessage: () => {} };
    +          vscodeApi.postMessage({ command: 'updateMarkdown', args: ['/etc/passwd', 'evil'] });
    +        })()
    +      `;
    +      expect(() => JSON5.parse(exploitPayload)).toThrow();
    +    });
    +
    +    test('throws on template literal injection', () => {
    +      expect(() => JSON5.parse('`${alert("xss")}`')).toThrow();
    +    });
    +
    +    test('throws on new operator', () => {
    +      expect(() => JSON5.parse('new Function("alert(1)")')).toThrow();
    +    });
    +
    +    test('throws on arrow-function IIFE', () => {
    +      const payload = '(() => { return 1; })()';
    +      expect(() => JSON5.parse(payload)).toThrow();
    +    });
    +
    +    test('throws on empty string', () => {
    +      expect(() => JSON5.parse('')).toThrow();
    +    });
    +  });
    +
    +  describe('safety: JSON5 does not execute code', () => {
    +    test('does not execute side effects in object values', () => {
    +      const sideEffect = false;
    +      const input = '{"key": "value"}';
    +      JSON5.parse(input);
    +      expect(sideEffect).toBe(false);
    +    });
    +
    +    test('rejects code disguised as a JSON value', () => {
    +      const payload = '{"signal": (function(){ return []; })()}';
    +      expect(() => JSON5.parse(payload)).toThrow();
    +    });
    +  });
    +});
    
  • test/wavedrom-source.test.ts+91 0 added
    @@ -0,0 +1,91 @@
    +import { normalizeWavedromSource } from '../src/renderers/wavedrom-source';
    +
    +describe('normalizeWavedromSource (shd101wyy/vscode-markdown-preview-enhanced#2315)', () => {
    +  describe('accepts and normalizes valid WaveDrom data', () => {
    +    it('passes through strict JSON unchanged in meaning', () => {
    +      expect(normalizeWavedromSource('{"signal":[]}')).toBe('{"signal":[]}');
    +    });
    +
    +    it('normalizes unquoted keys to strict JSON', () => {
    +      expect(normalizeWavedromSource('{ signal: [] }')).toBe('{"signal":[]}');
    +    });
    +
    +    it('normalizes single-quoted strings, trailing commas, and comments', () => {
    +      const out = normalizeWavedromSource(`{
    +        // clock
    +        signal: [
    +          { name: 'clk', wave: 'p..', },
    +        ],
    +      }`);
    +      expect(out).toBe('{"signal":[{"name":"clk","wave":"p.."}]}');
    +    });
    +
    +    it('accepts the reg root used by bitfield-style diagrams', () => {
    +      expect(normalizeWavedromSource('{ reg: [ { bits: 8 } ] }')).toBe(
    +        '{"reg":[{"bits":8}]}',
    +      );
    +    });
    +
    +    it('preserves hex numbers as their decimal value', () => {
    +      expect(normalizeWavedromSource('{ addr: 0xFF }')).toBe('{"addr":255}');
    +    });
    +  });
    +
    +  describe('rejects non-data / executable input', () => {
    +    it('returns null for a function-call payload', () => {
    +      expect(normalizeWavedromSource('alert(1)')).toBeNull();
    +    });
    +
    +    it('returns null for an IIFE', () => {
    +      expect(
    +        normalizeWavedromSource('(()=>{return globalThis.process})()'),
    +      ).toBeNull();
    +    });
    +
    +    it('returns null for constructor-escape payloads', () => {
    +      expect(
    +        normalizeWavedromSource('this.constructor.constructor("return 1")()'),
    +      ).toBeNull();
    +    });
    +
    +    it('returns null for bare scalars (not a diagram object)', () => {
    +      expect(normalizeWavedromSource('42')).toBeNull();
    +      expect(normalizeWavedromSource('"clk"')).toBeNull();
    +      expect(normalizeWavedromSource('null')).toBeNull();
    +    });
    +
    +    it('returns null for a top-level array root', () => {
    +      expect(normalizeWavedromSource('[{ name: "clk" }]')).toBeNull();
    +    });
    +
    +    it('returns null rather than silently corrupting non-finite numbers', () => {
    +      // JSON5 accepts Infinity/NaN but strict JSON cannot represent them;
    +      // drop the diagram instead of emitting `null` for the value.
    +      expect(normalizeWavedromSource('{ max: Infinity }')).toBeNull();
    +      expect(normalizeWavedromSource('{ min: -Infinity }')).toBeNull();
    +      expect(normalizeWavedromSource('{ x: NaN }')).toBeNull();
    +    });
    +
    +    it('returns null for empty / whitespace input', () => {
    +      expect(normalizeWavedromSource('')).toBeNull();
    +      expect(normalizeWavedromSource('   ')).toBeNull();
    +    });
    +  });
    +
    +  describe('neutralizes </script> breakout', () => {
    +    it('escapes < so a </script> string value cannot close the container', () => {
    +      const out = normalizeWavedromSource(
    +        '{ "name": "</script><img src=x onerror=alert(1)>" }',
    +      );
    +      expect(out).not.toBeNull();
    +      expect(out).not.toContain('</script>');
    +      expect(out).toContain('\\u003c/script>');
    +    });
    +
    +    it('produces output that is still valid JSON round-tripping the data', () => {
    +      const out = normalizeWavedromSource('{ "n": "a<b" }');
    +      expect(out).toBe('{"n":"a\\u003cb"}');
    +      expect(JSON.parse(out as string)).toEqual({ n: 'a<b' });
    +    });
    +  });
    +});
    
47fab742f15f

feat: add markdown-it callout feature with styling (#387)

https://github.com/shd101wyy/crossnoteMoyuMar 15, 2026via body-scan
5 files changed · +350 1
  • .gitignore+0 1 modified
    @@ -12,5 +12,4 @@ pnpm-debug.log
     mume
     .crossnote
     crossnote
    -styles/**/*.css
     docs
    
  • src/custom-markdown-it-features/callout.ts+173 0 added
    @@ -0,0 +1,173 @@
    +import MarkdownIt from 'markdown-it';
    +import Token from 'markdown-it/lib/token';
    +
    +export default (md: MarkdownIt) => {
    +  const _calloutTypes = new Set([
    +    'note',
    +    'summary',
    +    'abstract',
    +    'tldr',
    +    'info',
    +    'todo',
    +    'hint',
    +    'tip',
    +    'important',
    +    'check',
    +    'done',
    +    'success',
    +    'help',
    +    'question',
    +    'faq',
    +    'attention',
    +    'caution',
    +    'warning',
    +    'fail',
    +    'failure',
    +    'missing',
    +    'danger',
    +    'error',
    +    'bug',
    +    'example',
    +    'cite',
    +    'quote',
    +  ]);
    +  const _calloutTitleMap: Record<string, string> = {
    +    note: 'Note',
    +    summary: 'Summary',
    +    abstract: 'Abstract',
    +    tldr: 'TL;DR',
    +    info: 'Info',
    +    todo: 'Todo',
    +    hint: 'Hint',
    +    tip: 'Tip',
    +    important: 'Important',
    +    check: 'Check',
    +    done: 'Done',
    +    success: 'Success',
    +    help: 'Help',
    +    question: 'Question',
    +    faq: 'FAQ',
    +    attention: 'Attention',
    +    caution: 'Caution',
    +    warning: 'Warning',
    +    fail: 'Fail',
    +    failure: 'Failure',
    +    missing: 'Missing',
    +    danger: 'Danger',
    +    error: 'Error',
    +    bug: 'Bug',
    +    example: 'Example',
    +    cite: 'Cite',
    +    quote: 'Quote',
    +  };
    +
    +  // replace blockquote renderer
    +  const originalBlockquoteOpen =
    +    md.renderer.rules.blockquote_open || (() => '<blockquote>\n');
    +  const originalBlockquoteClose =
    +    md.renderer.rules.blockquote_close || (() => '</blockquote>\n');
    +
    +  // find the matching blockquote_close token and mark it
    +  const markCalloutCloseToken = (
    +    tokens: Token[],
    +    openIdx: number,
    +    calloutTag: 'div' | 'details',
    +  ) => {
    +    const openToken = tokens[openIdx];
    +    const targetLevel = openToken.level;
    +    for (let i = openIdx + 1; i < tokens.length; i += 1) {
    +      const token = tokens[i];
    +      if (token.type === 'blockquote_close' && token.level === targetLevel) {
    +        token.meta = { ...(token.meta || {}), callout: true, calloutTag };
    +        return;
    +      }
    +    }
    +  };
    +
    +  md.renderer.rules.blockquote_open = (tokens, idx, options, env, self) => {
    +    const token = tokens[idx];
    +    // check if it's a callout: see if the first child token is a paragraph and starts with [!
    +    let isCallout = false;
    +    let calloutType = 'info';
    +    let title = '';
    +    let foldable: 'open' | 'closed' | null = null;
    +
    +    // find the next non-empty token
    +    const nextToken = tokens[idx + 1];
    +    if (nextToken && nextToken.type === 'paragraph_open') {
    +      const textToken = tokens[idx + 2]; // inline token
    +      if (textToken && textToken.type === 'inline') {
    +        const content = textToken.content;
    +
    +        // use regex to match the callout pattern: [!type]+ optional title
    +        const match = content.match(
    +          /^\[!(\w+)\]([+-])?(?:[ \t]+([^\r\n]+))?(?:\r?\n|$)/,
    +        );
    +        if (match && _calloutTypes.has(match[1].toLowerCase())) {
    +          isCallout = true;
    +          calloutType = match[1].toLowerCase();
    +          foldable =
    +            match[2] === '+' ? 'open' : match[2] === '-' ? 'closed' : null;
    +          title = match[3] || '';
    +
    +          // remove the callout marker and "\n" from the inline token's children
    +          textToken.children =
    +            textToken.children?.filter((_, i) => i > 1) || null;
    +
    +          const remainingChildren = textToken.children;
    +          const isEmptyParagraph =
    +            !remainingChildren ||
    +            remainingChildren.length === 0 ||
    +            remainingChildren.every(
    +              (child) =>
    +                child.type === 'softbreak' || child.type === 'hardbreak',
    +            );
    +
    +          if (isEmptyParagraph) {
    +            const paragraphOpen = tokens[idx + 1];
    +            const paragraphClose = tokens[idx + 3];
    +            if (paragraphOpen) {
    +              paragraphOpen.hidden = true;
    +            }
    +            textToken.hidden = true;
    +            if (paragraphClose) {
    +              paragraphClose.hidden = true;
    +            }
    +          }
    +        }
    +      }
    +    } else {
    +      isCallout = false;
    +    }
    +
    +    if (isCallout) {
    +      const calloutTag = foldable ? 'details' : 'div';
    +      token.meta = { callout: true, type: calloutType, title, calloutTag };
    +      markCalloutCloseToken(tokens, idx, calloutTag);
    +      const displayTitle = title || _calloutTitleMap[calloutType];
    +      if (foldable) {
    +        const openAttr = foldable === 'open' ? ' open' : '';
    +        let html = `<details class="callout" data-callout="${calloutType}"${openAttr}>\n`;
    +        html += `<summary class="callout-title">${md.utils.escapeHtml(displayTitle)}</summary>\n`;
    +        return html;
    +      }
    +
    +      let html = `<div class="callout" data-callout="${calloutType}">\n`;
    +      if (displayTitle) {
    +        html += `<div class="callout-title">${md.utils.escapeHtml(displayTitle)}</div>\n`;
    +      }
    +      return html;
    +    } else {
    +      return originalBlockquoteOpen(tokens, idx, options, env, self);
    +    }
    +  };
    +
    +  md.renderer.rules.blockquote_close = (tokens, idx, options, env, self) => {
    +    if (tokens[idx].meta?.callout) {
    +      return tokens[idx].meta?.calloutTag === 'details'
    +        ? '</details>\n'
    +        : '</div>\n';
    +    }
    +    return originalBlockquoteClose(tokens, idx, options, env, self);
    +  };
    +};
    
  • src/markdown-engine/index.ts+18 0 modified
    @@ -536,6 +536,15 @@ window["initRevealPresentation"] = async function() {
           vscodePreviewPanel,
         )}">`;
     
    +    // style markdown-it-callout
    +    styles += `<link rel="stylesheet" media="screen" href="${utility.addFileProtocol(
    +      path.resolve(
    +        utility.getCrossnoteBuildDirectory(),
    +        './styles/markdown-it-callout.css',
    +      ),
    +      vscodePreviewPanel,
    +    )}">`;
    +
         // global styles
         styles += `<style>${this.notebook.config.globalCss}</style>`;
     
    @@ -1773,6 +1782,15 @@ sidebarTOCBtn.addEventListener('click', function(event) {
                   ),
                 )
               : '',
    +        // markdown-it-callout
    +        outputHTML.indexOf('callout') > 0
    +          ? await this.fs.readFile(
    +              path.resolve(
    +                utility.getCrossnoteBuildDirectory(),
    +                './styles/markdown-it-callout.css',
    +              ),
    +            )
    +          : '',
           ]);
           styleCSS = styles.join('');
         } catch (e) {
    
  • src/notebook/index.ts+2 0 modified
    @@ -11,6 +11,7 @@ import Token from 'markdown-it/lib/token';
     import * as path from 'path';
     import { URI, Utils } from 'vscode-uri';
     import useMarkdownAdmonition from '../custom-markdown-it-features/admonition';
    +import useMarkdownCallout from '../custom-markdown-it-features/callout';
     import useMarkdownItCodeFences from '../custom-markdown-it-features/code-fences';
     import useMarkdownItCriticMarkup from '../custom-markdown-it-features/critic-markup';
     import useMarkdownItCurlyBracketAttributes from '../custom-markdown-it-features/curly-bracket-attributes';
    @@ -158,6 +159,7 @@ export class Notebook {
         useMarkdownItMath(md, this);
         useMarkdownItWikilink(md, this);
         useMarkdownAdmonition(md);
    +    useMarkdownCallout(md);
         useMarkdownItSourceMap(md);
         useMarkdownItWidget(md, this);
         return md;
    
  • styles/markdown-it-callout.css+157 0 added
    @@ -0,0 +1,157 @@
    +@font-face {
    +  font-family: "Material Icons";
    +  font-style: normal;
    +  font-weight: 400;
    +  src: local("Material Icons"), local("MaterialIcons-Regular"), url("data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAfIAAsAAAAADDAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7kosY21hcAAAAYAAAADTAAACjtP6ytBnbHlmAAACVAAAAxgAAAQ4zRtvlGhlYWQAAAVsAAAALwAAADYRwZsnaGhlYQAABZwAAAAcAAAAJAeKAzxobXR4AAAFuAAAABIAAAA8OGQAAGxvY2EAAAXMAAAAIAAAACAG5AfwbWF4cAAABewAAAAfAAAAIAEfAERuYW1lAAAGDAAAAVcAAAKFkAhoC3Bvc3QAAAdkAAAAYgAAAK2vz7wkeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkPsQ4gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVLy4xKzzX4chhrmK4QpQmBEkBwAZygyweJzFkr0NwjAQhZ+TEP6CRUfHBEwRUWaQTICyQbpMwRCskA5RUIONxG0RnnNpKAIV4qzPku/8c353ACYAYrIjCWCuMAh2ptf0/hiL3p/gyPUWa3osqlt0L1zu9r71z8dGrJRykFoauXQd932Lj5vhG+MjxGeYI8MKETObMpslf5EyP8tg+vHun5r539PvlvXzaVhRFVQDTPEWKVQR90KhnnC5Ek67vUKN4VuFasM/ldARj43CCkCsEjpJSoVVgRyU0GVSK6wUpFFCx8lFgX0BiXpRPQB4nE2TTWjcRhTH3xttpDhxN7uxPlp3u/FK7moRPixafRijNosxSw/LUsIwNcaEHPZggo/FmEKMCKWU4kNOOftQSlhE8alnH0Ix9BqWnHooPRrTQ0+mnu2bXTu2pPdGM9LM/6c3fwECTM4gBBMYQNqxzLrZAjqYSlqu2TAHZQA0/DQJH6FtzqGDnvbt4Ggwvzw/nL8EfH8kW0fsuRqhgWXZnY7M1picaUL7Du5BHeDzMIl83dAt016wH1qmvtSMo5R6YRJHTR//FXsff/nj/tc/5K9P5d+nP22+fFK5u7v3K39SW3y+OtDKO3L85vD09PD9z5X17a2N1g4tqk01RlqX7gyoEmnsWQtVr4rtZMmukEaFBZxzefkCn11cyKMLZgshRwgTYNoLNXCBz2ja7HvZG7hDpPSNfoo5vs0knK/9hb+rNpu+8kHPgk/Ao4kK3tWtTpSEtvkA9c+wE6UaUdwieNkaHg55tBEtRiEPw1s0+FtrtTcc9two2lhMknV7PZF/cs6+uUFTmpTGbEx7sQCPSLOttHS3GRltqp7SNzVSKzl6aWnZT/CX5k6/v9N3Hh8fHBwffJVjhrC6OgH5dkIt/tPsq+d/PD5Qz7G7efzq1THFjdZVPe/N6ulQ3JnDWSE5junsFsVIiFwL/htf1S5gJ3BfOcUxfHKLnzqpFpyfZ9cX+/5WB6a+Y0pHpzkNrYNVDwMsikK+y7WuLCRg/oFHkA8VT3rDg5ZnU6ktzzINymV0m74Xd5pfIGXyFeVEQSShkzqG7TBBa2OxVRKitLXv7h3uuftXnXq7lz2tZ/WnWa9dx9dCjDhHzmuVQATlmljr9dZErUydSo2Hbi/b1vXtrOeGCk2/8s3ZlO8+ueJT8BVlw5pGw2oYccdSiHHqx0RlabHqdNR9jAETl6PreJcPBnnfpTLnOQ8C3OV8AmQGzouV1iZdeb5SSIoVc8W8/kcDtksUH5FrU6/aqBqNWcMEzxG4DAQ14qRQhi9mWU0rzepKezbjfgCwQKxVYq5ajRgpRqy45CqwkJydcEkbTkvRz8P5/2ZpDTN4nGNgZGBgAOKb6v+/xvPbfGXgZmEAgeuB2kkI+v8bFgbmKiCXg4EJJAoAPyAKhQB4nGNgZGBg1vmvwxDDwgACQJKRARXwAwAzZQHQeJxjYQCCFAYGFgbSMQAcWACdAAAAAAAAAAwALgBgAIQAmADSAQgBIgE8AVABoAHeAfwCHHicY2BkYGDgZ7BgYGMAASYg5gJCBob/YD4DAA/hAWQAeJxlkbtuwkAURMc88gApQomUJoq0TdIQzEOpUDokKCNR0BuzBiO/tF6QSJcPyHflE9Klyyekz2CuG8cr7547M3d9JQO4xjccnJ57vid2cMHqxDWc40G4Tv1JuEF+Fm6ijRfhM+oz4Ra6eBVu4wZvvMFpXLIa40PYQQefwjVc4Uu4Tv1HuEH+FW7i1mkKn6Hj3Am3sHC6wm08Ou8tpSZGe1av1PKggjSxPd8zJtSGTuinyVGa6/Uu8kxZludCmzxMEzV0B6U004k25W35fj2yNlCBSWM1paujKFWZSbfat+7G2mzc7weiu34aczzFNYGBhgfLfcV6iQP3ACkSaj349AxXSN9IT0j16JepOb01doiKbNWt1ovippz6sVYYwsXgX2rGVFIkq7Pl2PNrI6qW6eOshj0xaSq9mpNEZIWs8LZUfOouNkVXxp/d5woqebeYIf4D2J1ywQB4nG3LOw6AIBAE0B384B+PAkgEa+QwNnYmHt+EpXSal5lkSBBnoP8oCFSo0aCFRIceA0ZMmLFAYSW88rmvtMUjG3RiQ9HvpfusM6zWNmtc5H/iPewha50tOt5PS/QBx2IeSwAA") format("woff");
    +}
    +
    +
    +.callout {
    +  --callout-color: 68, 138, 255;
    +  position: relative;
    +  overflow: hidden;
    +  border-radius: 4px;
    +  margin: 1rem 0;
    +  padding: 0.75rem 1rem;
    +  background: rgba(var(--callout-color), 0.1);
    +}
    +
    +.callout>.callout-title {
    +  margin: 0 -1.2rem;
    +  padding: 0rem 1.2rem 0rem 3.3rem;
    +  font-weight: 700;
    +  color: rgb(var(--callout-color));
    +}
    +
    +.callout .callout-title::before {
    +  position: absolute;
    +  left: 1.2rem;
    +  font-size: 1.2rem;
    +  font-family: Material Icons;
    +  font-style: normal;
    +  font-variant: normal;
    +  font-weight: 400;
    +  text-transform: none;
    +  white-space: nowrap;
    +  word-wrap: normal;
    +  direction: ltr;
    +  color: rgba(var(--callout-color), 0.8);
    +  content: var(--callout-icon, "i")
    +}
    +
    +.callout>p {
    +  margin-block-start: 1rem;
    +  margin-block-end: 1rem;
    +  padding-left: .4rem;
    +}
    +
    +.callout details.callout-title,
    +.callout summary.callout-title {
    +  cursor: pointer;
    +  list-style: none;
    +}
    +
    +.callout summary.callout-title::-webkit-details-marker {
    +  display: none;
    +}
    +
    +details.callout > summary.callout-title::after {
    +  display: inline-block;
    +  width: 0.45em;
    +  height: 0.45em;
    +  margin-left: 1em;
    +  border-right: 2px solid rgb(var(--callout-color));
    +  border-bottom: 2px solid rgb(var(--callout-color));
    +  transform: translateY(-0.05em) rotate(-45deg);
    +  transition: transform 160ms ease, opacity 160ms ease;
    +  opacity: 0.9;
    +  content: "";
    +}
    +
    +details.callout[open] > summary.callout-title::after {
    +  transform: translateY(-0.05em) rotate(45deg);
    +  opacity: 1;
    +}
    +
    +.callout[data-callout="summary"],
    +.callout[data-callout="tldr"],
    +.callout[data-callout="abstract"] {
    +  --callout-color: 0, 191, 188;
    +  --callout-icon: "\E8D2";
    +}
    +
    +.callout[data-callout="note"] {
    +  --callout-color: 8, 109, 221;
    +  --callout-icon: "\E3C9";
    +}
    +
    +.callout[data-callout="info"] {
    +  --callout-color: 8, 109, 221;
    +  --callout-icon: "\E88E";
    +}
    +
    +.callout[data-callout="todo"] {
    +  --callout-color: 8, 109, 221;
    +  --callout-icon: "\E88E";
    +}
    +
    +.callout[data-callout="hint"],
    +.callout[data-callout="important"],
    +.callout[data-callout="tip"] {
    +  --callout-color: 0, 191, 188;
    +  --callout-icon: "\E80E";
    +}
    +
    +.callout[data-callout="check"],
    +.callout[data-callout="done"],
    +.callout[data-callout="success"] {
    +  --callout-color: 8, 185, 78;
    +  --callout-icon: "\E876";
    +}
    +
    +.callout[data-callout="help"],
    +.callout[data-callout="faq"],
    +.callout[data-callout="question"] {
    +  --callout-color: 236, 117, 0;
    +  --callout-icon: "\E887";
    +}
    +
    +.callout[data-callout="caution"],
    +.callout[data-callout="attention"],
    +.callout[data-callout="warning"] {
    +  --callout-color: 236, 117, 0;
    +  --callout-icon: "\E002";
    +}
    +
    +.callout[data-callout="fail"],
    +.callout[data-callout="missing"],
    +.callout[data-callout="failure"] {
    +  --callout-color: 233, 49, 71;
    +  --callout-icon: "\E14C";
    +}
    +
    +.callout[data-callout="error"],
    +.callout[data-callout="danger"] {
    +  --callout-color: 233, 49, 71;
    +  --callout-icon: "\E3E7";
    +}
    +
    +.callout[data-callout="bug"] {
    +  --callout-color: 233, 49, 71;
    +  --callout-icon: "\E868";
    +}
    +
    +.callout[data-callout="example"] {
    +  --callout-color: 120, 82, 238;
    +  --callout-icon: "\E242";
    +}
    +
    +.callout[data-callout="cite"],
    +.callout[data-callout="quote"] {
    +  --callout-color: 158, 158, 158;
    +  --callout-icon: "\E244";
    +}
    +
    +.callout .callout {
    +  margin: 0.75rem 0;
    +}
    
d0cf068448ab

fix: Remove the wrapper of custom head in HTML page. (#386)

https://github.com/shd101wyy/crossnoteTanShunMar 15, 2026via body-scan
1 file changed · +2 1
  • src/markdown-engine/index.ts+2 1 modified
    @@ -2111,7 +2111,8 @@ sidebarTOCBtn.addEventListener('click', function(event) {
             }
           }
         }
    -    return $.html();
    +    // Return only the head content, not the full HTML structure
    +    return $('head').html() || header;
       }
     
       /**
    
9cce7652d065

Merge 7ac6fb3048399a64a431d9c57fcf7419db0bd131 into fab91566e7b236c3dfde38d1c6a86253ef4501b0

5 files changed · +266 3
  • package.json+10 0 modified
    @@ -594,6 +594,16 @@
               "default": "https://kroki.io",
               "type": "string"
             },
    +        "markdown-preview-enhanced.webSequenceDiagramsServer": {
    +          "description": "The URL of the WebSequenceDiagrams server to use for rendering wsd code blocks.",
    +          "default": "https://www.websequencediagrams.com",
    +          "type": "string"
    +        },
    +        "markdown-preview-enhanced.webSequenceDiagramsApiKey": {
    +          "description": "API key for WebSequenceDiagrams. Required for wider diagram sizes.",
    +          "default": "",
    +          "type": "string"
    +        },
             "markdown-preview-enhanced.markdownFileExtensions": {
               "description": "Markdown file extensions. This is used to determine whether to show the preview button in the markdown file context menu.",
               "default": [
    
  • README.md+1 1 modified
    @@ -38,7 +38,7 @@ These [GitHub Sponsors](https://github.com/sponsors/shd101wyy#sponsors) and [Bac
     
     ## Introduction
     
    -Markdown Preview Enhanced is an extension that provides you with many useful functionalities such as automatic scroll sync, [math typesetting](https://shd101wyy.github.io/markdown-preview-enhanced/#/math), [mermaid](https://shd101wyy.github.io/markdown-preview-enhanced/#/diagrams?id=mermaid), [PlantUML](https://shd101wyy.github.io/markdown-preview-enhanced/#/diagrams?id=plantuml), [pandoc](https://shd101wyy.github.io/markdown-preview-enhanced/#/pandoc), PDF export, [code chunk](https://shd101wyy.github.io/markdown-preview-enhanced/#/code-chunk), [presentation writer](https://rawgit.com/shd101wyy/markdown-preview-enhanced/master/docs/presentation-intro.html), etc. A lot of its ideas are inspired by [Markdown Preview Plus](https://github.com/atom-community/markdown-preview-plus) and [RStudio Markdown](http://rmarkdown.rstudio.com/).
    +Markdown Preview Enhanced is an extension that provides you with many useful functionalities such as automatic scroll sync, [math typesetting](https://shd101wyy.github.io/markdown-preview-enhanced/#/math), [mermaid](https://shd101wyy.github.io/markdown-preview-enhanced/#/diagrams?id=mermaid), [PlantUML](https://shd101wyy.github.io/markdown-preview-enhanced/#/diagrams?id=plantuml), [WebSequenceDiagrams](https://www.websequencediagrams.com), [pandoc](https://shd101wyy.github.io/markdown-preview-enhanced/#/pandoc), PDF export, [code chunk](https://shd101wyy.github.io/markdown-preview-enhanced/#/code-chunk), [presentation writer](https://rawgit.com/shd101wyy/markdown-preview-enhanced/master/docs/presentation-intro.html), etc. A lot of its ideas are inspired by [Markdown Preview Plus](https://github.com/atom-community/markdown-preview-plus) and [RStudio Markdown](http://rmarkdown.rstudio.com/).
     
     Feel free to ask questions, post issues, submit pull request, and request new features.
     
    
  • src/config.ts+9 0 modified
    @@ -37,6 +37,8 @@ type VSCodeMPEConfigKey =
       | 'qiniuDomain'
       | 'qiniuSecretKey'
       | 'scrollSync'
    +  | 'webSequenceDiagramsServer'
    +  | 'webSequenceDiagramsApiKey'
       | 'disableAutoPreviewForUriSchemes';
     
     type ConfigKey = keyof NotebookConfig | VSCodeMPEConfigKey;
    @@ -89,6 +91,8 @@ export class MarkdownPreviewEnhancedConfig implements NotebookConfig {
       public readonly plantumlJarPath: string;
       public readonly jsdelivrCdnHost: string;
       public readonly krokiServer: string;
    +  public readonly webSequenceDiagramsServer: string;
    +  public readonly webSequenceDiagramsApiKey: string;
       public readonly alwaysShowBacklinksInPreview: boolean;
       public readonly enablePreviewZenMode: boolean;
       public readonly wikiLinkTargetFileExtension: string;
    @@ -249,6 +253,11 @@ export class MarkdownPreviewEnhancedConfig implements NotebookConfig {
           getMPEConfig<string>('jsdelivrCdnHost') ?? defaultConfig.jsdelivrCdnHost;
         this.krokiServer =
           getMPEConfig<string>('krokiServer') ?? defaultConfig.krokiServer;
    +    this.webSequenceDiagramsServer =
    +      getMPEConfig<string>('webSequenceDiagramsServer') ||
    +      'https://www.websequencediagrams.com';
    +    this.webSequenceDiagramsApiKey =
    +      getMPEConfig<string>('webSequenceDiagramsApiKey') || '';
         this.alwaysShowBacklinksInPreview =
           getMPEConfig<boolean>('alwaysShowBacklinksInPreview') ??
           defaultConfig.alwaysShowBacklinksInPreview;
    
  • src/preview-provider.ts+15 2 modified
    @@ -15,6 +15,7 @@ import {
       isVSCodeWebExtension,
       isVSCodewebExtensionDevMode,
     } from './utils';
    +import { processWsdBlocks } from './wsd';
     
     if (isVSCodeWebExtension()) {
       console.debug('* Using crossnote version: ', getCrossnoteVersion());
    @@ -141,6 +142,18 @@ export class PreviewProvider {
         return PreviewProvider.notebooksManager;
       }
     
    +  /**
    +   * Replace ```wsd code blocks in the rendered HTML with
    +   * <img> tags pointing to the WebSequenceDiagrams server.
    +   */
    +  private applyWsdProcessing(html: string): string {
    +    const server =
    +      getMPEConfig<string>('webSequenceDiagramsServer') ||
    +      'https://www.websequencediagrams.com';
    +    const apiKey = getMPEConfig<string>('webSequenceDiagramsApiKey') || '';
    +    return processWsdBlocks(html, server, apiKey || undefined);
    +  }
    +
       public static async getPreviewContentProvider(
         uri: vscode.Uri,
         context: vscode.ExtensionContext,
    @@ -434,7 +447,7 @@ export class PreviewProvider {
             vscodePreviewPanel: previewPanel,
             isVSCodeWebExtension: isVSCodeWebExtension(),
           });
    -      previewPanel.webview.html = html;
    +      previewPanel.webview.html = this.applyWsdProcessing(html);
         } catch (error) {
           vscode.window.showErrorMessage(error.toString());
           console.error(error);
    @@ -558,7 +571,7 @@ export class PreviewProvider {
                 await this.postMessageToPreview(sourceUri, {
                   command: 'updateHtml',
                   markdown: text,
    -              html,
    +              html: this.applyWsdProcessing(html),
                   tocHTML,
                   totalLineCount: document.lineCount,
                   sourceUri: sourceUri.toString(),
    
  • src/wsd.ts+231 0 added
    @@ -0,0 +1,231 @@
    +/**
    + * WebSequenceDiagrams (WSD) support.
    + *
    + * Encodes diagram text using LZ77 compression + URL-safe Base64 encoding,
    + * then builds a URL to the WSD server's image-rendering endpoint.
    + *
    + * Reference: https://www.websequencediagrams.com
    + */
    +
    +const BASE64_TABLE =
    +  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
    +
    +class BitWriter {
    +  private str = '';
    +  private partial = 0;
    +  private partialSize = 0;
    +
    +  addBits(bits: number, size: number): void {
    +    this.partial = (this.partial << size) | bits;
    +    this.partialSize += size;
    +    while (this.partialSize >= 6) {
    +      this.str += BASE64_TABLE.charAt(
    +        (this.partial >> (this.partialSize - 6)) & 0x3f,
    +      );
    +      this.partialSize -= 6;
    +    }
    +  }
    +
    +  finish(): string {
    +    if (this.partialSize) {
    +      this.str += BASE64_TABLE.charAt(
    +        (this.partial << (6 - this.partialSize)) & 0x3f,
    +      );
    +      this.partialSize = 0;
    +      this.partial = 0;
    +    }
    +    return this.str;
    +  }
    +}
    +
    +function encodeBase64(str: string): string {
    +  const writer = new BitWriter();
    +  for (let n = 0; n < str.length; n++) {
    +    writer.addBits(str.charCodeAt(n), 8);
    +  }
    +  return writer.finish();
    +}
    +
    +function encodeUtf8(input: string): string {
    +  const normalized = input.replace(/\r\n/g, '\n');
    +  let utftext = '';
    +
    +  for (let n = 0; n < normalized.length; n++) {
    +    const c = normalized.charCodeAt(n);
    +
    +    if (c < 128) {
    +      utftext += String.fromCharCode(c);
    +    } else if (c > 127 && c < 2048) {
    +      utftext += String.fromCharCode((c >> 6) | 192);
    +      utftext += String.fromCharCode((c & 63) | 128);
    +    } else {
    +      utftext += String.fromCharCode((c >> 12) | 224);
    +      utftext += String.fromCharCode(((c >> 6) & 63) | 128);
    +      utftext += String.fromCharCode((c & 63) | 128);
    +    }
    +  }
    +
    +  return utftext;
    +}
    +
    +function encodeNumber(num: number): string {
    +  if (num >= 0x3fff) {
    +    return (
    +      String.fromCharCode(0x80 | ((num >> 14) & 0x7f)) +
    +      String.fromCharCode(0x80 | ((num >> 7) & 0x7f)) +
    +      String.fromCharCode(num & 0x7f)
    +    );
    +  } else if (num >= 0x7f) {
    +    return (
    +      String.fromCharCode(0x80 | ((num >> 7) & 0x7f)) +
    +      String.fromCharCode(num & 0x7f)
    +    );
    +  } else {
    +    return String.fromCharCode(num);
    +  }
    +}
    +
    +function encodeLz77(input: string): string {
    +  const MinStringLength = 4;
    +  let output = '';
    +  let pos = 0;
    +  const hash: { [key: string]: number[] } = {};
    +
    +  const lastPos = input.length - MinStringLength;
    +
    +  for (let i = MinStringLength; i < input.length; i++) {
    +    const subs = input.substr(i - MinStringLength, MinStringLength);
    +    if (hash[subs] === undefined) {
    +      hash[subs] = [];
    +    }
    +    hash[subs].push(i - MinStringLength);
    +  }
    +
    +  while (pos < lastPos) {
    +    let matchLength = MinStringLength;
    +    let foundMatch = false;
    +    const bestMatch = { distance: 0, length: 0 };
    +    const prefix = input.substr(pos, MinStringLength);
    +    const matches = hash[prefix];
    +
    +    if (matches !== undefined) {
    +      for (let i = 0; i < matches.length; i++) {
    +        const searchStart = matches[i];
    +        if (searchStart + matchLength >= pos) {
    +          break;
    +        }
    +
    +        while (searchStart + matchLength < pos) {
    +          const isValidMatch =
    +            input.substr(searchStart, matchLength) ===
    +            input.substr(pos, matchLength);
    +          if (isValidMatch) {
    +            const realMatchLength = matchLength;
    +            matchLength++;
    +            if (foundMatch && realMatchLength > bestMatch.length) {
    +              bestMatch.distance = pos - searchStart - realMatchLength;
    +              bestMatch.length = realMatchLength;
    +            }
    +            foundMatch = true;
    +          } else {
    +            break;
    +          }
    +        }
    +      }
    +    }
    +
    +    if (bestMatch.length) {
    +      output +=
    +        String.fromCharCode(0) +
    +        encodeNumber(bestMatch.distance) +
    +        encodeNumber(bestMatch.length);
    +      pos += bestMatch.length;
    +    } else {
    +      if (input.charCodeAt(pos) !== 0) {
    +        output += input.charAt(pos);
    +      } else {
    +        output += String.fromCharCode(0) + String.fromCharCode(0);
    +      }
    +      pos++;
    +    }
    +  }
    +
    +  return output + input.slice(pos).replace(/\0/g, '\0\0');
    +}
    +
    +/**
    + * Encode diagram text into the compressed `lz` parameter
    + * used by websequencediagrams.com.
    + */
    +export function encodeWsdText(text: string): string {
    +  return encodeBase64(encodeLz77(encodeUtf8(text)));
    +}
    +
    +/**
    + * Build the full image URL for a WSD diagram.
    + *
    + * @param text     Raw diagram source
    + * @param server   WSD server base URL (no trailing slash)
    + * @param style    Optional diagram style (e.g. "default", "modern-blue", "napkin")
    + * @param apiKey   Optional API key for premium styles
    + */
    +export function buildWsdImageUrl(
    +  text: string,
    +  server: string,
    +  style?: string,
    +  apiKey?: string,
    +): string {
    +  const encoded = encodeWsdText(text);
    +  let url = `${server}/cgi-bin/cdraw?lz=${encoded}`;
    +  if (style) {
    +    url += `&s=${style}`;
    +  }
    +  if (apiKey) {
    +    url += `&apikey=${apiKey}`;
    +  }
    +  return url;
    +}
    +
    +/**
    + * Decode common HTML entities back to their literal characters.
    + */
    +function decodeHtmlEntities(html: string): string {
    +  return html
    +    .replace(/&amp;/g, '&')
    +    .replace(/&lt;/g, '<')
    +    .replace(/&gt;/g, '>')
    +    .replace(/&quot;/g, '"')
    +    .replace(/&#39;/g, "'")
    +    .replace(/&#x27;/g, "'")
    +    .replace(/&#x2F;/g, '/');
    +}
    +
    +/**
    + * Post-process rendered HTML: find `wsd` code blocks and replace them
    + * with `<img>` tags pointing at the WSD server.
    + *
    + * The crossnote engine emits unrecognised fenced blocks as:
    + *   <pre ... data-role="codeBlock" data-info="wsd" ...>content</pre>
    + *
    + * This function converts each one to a rendered diagram image.
    + */
    +export function processWsdBlocks(
    +  html: string,
    +  server: string,
    +  apiKey?: string,
    +): string {
    +  // Match <pre> elements whose data-info attribute starts with "wsd"
    +  const pattern =
    +    /<pre\b[^>]*?\bdata-info="wsd(?:\s[^"]*)?"[^>]*>([\s\S]*?)<\/pre>/gi;
    +
    +  return html.replace(pattern, (_match, content: string) => {
    +    // Strip HTML tags (e.g. Prism.js syntax-highlight spans) to recover raw text
    +    const rawText = decodeHtmlEntities(content.replace(/<[^>]*>/g, '')).trim();
    +    if (!rawText) {
    +      return '<div class="wsd-diagram"><em>Empty WSD diagram</em></div>';
    +    }
    +
    +    const imgUrl = buildWsdImageUrl(rawText, server, 'rose', apiKey);
    +    return `<div class="wsd-diagram"><img src="${imgUrl}" alt="Sequence Diagram"></div>`;
    +  });
    +}
    

Vulnerability mechanics

Root cause

"The WaveDrom rendering pipeline unsafely uses `window.eval()` to process user-controlled markdown content, allowing arbitrary JavaScript execution."

Attack vector

An attacker can craft a Markdown document containing a WaveDrom fenced code block with malicious JavaScript. When this document is previewed, the WaveDrom rendering pipeline passes the content of this block directly to `window.eval()` within the VS Code webview context [ref_id=2]. This script can then leverage the `vscodeApi` to send a message to the extension host, which blindly executes commands like `_crossnote.updateMarkdown`. This allows arbitrary file writes on the local filesystem, as demonstrated by overwriting `~/.ssh/authorized_keys` [ref_id=2].

Affected code

The vulnerability exists in the `renderWavedrom()` function where user-supplied text from WaveDrom fenced code blocks is passed to `window.eval()` [ref_id=2]. The HTML sanitizers in `crossnote/src/markdown-engine/sanitize.ts` and `crossnote/src/webview/lib/sanitize.ts` also preserved `<script type="WaveDrom">` tags, contributing to the bypass [ref_id=2]. The fix involves changes in `crossnote/src/webview/containers/preview.ts` and the sanitization logic.

What the fix does

The fix replaces the use of `window.eval()` with `JSON5.parse()` for processing WaveDrom content in the live preview [ref_id=1]. Additionally, the HTML sanitizer now validates and normalizes WaveDrom scripts to inert JSON, preventing malicious scripts from being executed even if injected via raw HTML. This ensures that only valid, non-executable data is processed, mitigating the arbitrary code execution vulnerability [ref_id=1, ref_id=3].

Preconditions

  • inputA Markdown document containing a WaveDrom fenced code block with a JavaScript payload.
  • configThe extension must be configured to render WaveDrom diagrams.

Generated on Jun 5, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.