minecodex 2.0.14 → 2.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -176,7 +176,8 @@ export function installMarkdownRichText(view, api, native, codex) {
176
176
  button.dataset.mcxFootnoteRef = this.options.id;
177
177
  button.addEventListener('click', (event) => {
178
178
  event.preventDefault();
179
- footnoteReturns.set(this.options.id, view.scrollDOM.scrollTop);
179
+ // 虚拟段落重新测量后像素高度会变化,使用原生文档锚点恢复阅读位置。
180
+ footnoteReturns.set(this.options.id, view.scrollSnapshot());
180
181
  jump(this.options.to);
181
182
  });
182
183
  sup.append(button);
@@ -201,8 +202,7 @@ export function installMarkdownRichText(view, api, native, codex) {
201
202
  const previous = footnoteReturns.get(this.options.id);
202
203
  if (previous === undefined) jump(this.options.to);
203
204
  else {
204
- view.scrollDOM.scrollTop = previous;
205
- view.requestMeasure();
205
+ view.dispatch({ effects: previous });
206
206
  }
207
207
  });
208
208
  element.append(back);
@@ -478,7 +478,14 @@ export function installMarkdownRichText(view, api, native, codex) {
478
478
  );
479
479
  }
480
480
  }
481
- const { definitions: footnotes, references } = collectMarkdownFootnotes(text, protectedRanges);
481
+ const { definitions: footnotes, references, definitionRanges } = collectMarkdownFootnotes(text, protectedRanges);
482
+ // 同名定义沿用最后一条;早期定义不再被误作引用或普通正文。
483
+ for (const note of definitionRanges) {
484
+ if (footnotes.get(note.id).from === note.from) continue;
485
+ replace(note.from, note.to);
486
+ for (let i = doc.lineAt(note.from).number; i <= doc.lineAt(note.to).number; i++)
487
+ hiddenLines.add(doc.line(i).from);
488
+ }
482
489
  for (const reference of references)
483
490
  replace(
484
491
  reference.from,
@@ -505,7 +512,7 @@ export function installMarkdownRichText(view, api, native, codex) {
505
512
  const line = doc.line(i);
506
513
  if (
507
514
  protectedAt(line.from) ||
508
- [...footnotes.values()].some((n) => line.from >= n.from && line.from <= n.to)
515
+ definitionRanges.some((n) => line.from >= n.from && line.from <= n.to)
509
516
  )
510
517
  continue;
511
518
  for (const m of line.text.matchAll(/(?<![\\$])\$(?![\s$])([^$\n]+?)(?<![\s\\])\$(?!\$)/g)) {
@@ -1,6 +1,17 @@
1
1
  import { loadNativeMarkdownRenderer } from './markdown-native.mjs';
2
2
  import { captureMarkdownProviders } from './providers.mjs';
3
3
 
4
+ export function markdownExportAlias(source, name) {
5
+ const start = source.lastIndexOf('export{');
6
+ if (start < 0) return undefined;
7
+ const entries = source.slice(start + 7).split('}')[0].split(',');
8
+ for (const entry of entries) {
9
+ const [local, alias = local] = entry.trim().split(/\s+as\s+/);
10
+ if (local === name) return alias;
11
+ }
12
+ return undefined;
13
+ }
14
+
4
15
  // 从 Chat Markdown 的公开组件发现悬浮操作栏和控件,不绑定构建 hash。
5
16
  export async function loadNativeMarkdownTableActions(native) {
6
17
  const url = [...document.querySelectorAll('link[rel="modulepreload"],script[src]')]
@@ -21,7 +32,7 @@ export async function loadNativeMarkdownTableActions(native) {
21
32
  const exported = source.slice(source.lastIndexOf('export{'));
22
33
  const module = await import(url);
23
34
  const publicBinding = (name) => {
24
- const alias = exported.match(new RegExp(`\\b${name} as ([\\w$]+)`))?.[1];
35
+ const alias = markdownExportAlias(exported, name);
25
36
  if (!alias || !module[alias]) throw new Error('native-table-actions-export-unavailable');
26
37
  return module[alias];
27
38
  };
@@ -56,7 +67,7 @@ export async function loadNativeMarkdownTableActions(native) {
56
67
  );
57
68
  if (wrapAt < 0 || !wrapPair) throw new Error('native-code-wrap-icons-unavailable');
58
69
  const sharedExports = sharedSource.slice(sharedSource.lastIndexOf('export{'));
59
- const sharedBinding = (name) => shared[sharedExports.match(new RegExp(`\\b${name} as ([\\w$]+)`))?.[1]];
70
+ const sharedBinding = (name) => shared[markdownExportAlias(sharedExports, name)];
60
71
  const assignment = sharedSource.indexOf(`${wrapPair[1]}=`);
61
72
  const initialize = sharedSource
62
73
  .slice(sharedSource.lastIndexOf('function ', assignment))
@@ -8,6 +8,7 @@ export function collectMarkdownFootnotes(text, excludedRanges) {
8
8
  });
9
9
  const excluded = (position) => excludedRanges.some(([from, to]) => position >= from && position < to);
10
10
  const definitions = new Map();
11
+ const definitionRanges = [];
11
12
  for (let index = 0; index < lines.length; index++) {
12
13
  const line = lines[index];
13
14
  const match = line.text.match(/^ {0,3}\[\^([^\]]+)\]:\s*(.*)$/);
@@ -25,6 +26,7 @@ export function collectMarkdownFootnotes(text, excludedRanges) {
25
26
  refs: [],
26
27
  number: 0,
27
28
  });
29
+ definitionRanges.push({ id: match[1], from: line.from, to: lines[end].to });
28
30
  index = end;
29
31
  }
30
32
  const notes = [...definitions.values()];
@@ -37,7 +39,7 @@ export function collectMarkdownFootnotes(text, excludedRanges) {
37
39
  escaped ||
38
40
  !note ||
39
41
  excluded(match.index) ||
40
- notes.some((note) => match.index >= note.from && match.index < note.to)
42
+ definitionRanges.some((note) => match.index >= note.from && match.index < note.to)
41
43
  )
42
44
  continue;
43
45
  if (!note.number) note.number = ++number;
@@ -52,5 +54,5 @@ export function collectMarkdownFootnotes(text, excludedRanges) {
52
54
  }
53
55
  // 没有引用的定义仍保留,沿用正文末尾的连续编号。
54
56
  for (const note of notes) if (!note.number) note.number = ++number;
55
- return { definitions, references };
57
+ return { definitions, references, definitionRanges };
56
58
  }
@@ -7,6 +7,7 @@ import {
7
7
  } from './adapters/codex/reading-runtime.mjs';
8
8
  import { loadNativeMarkdownRichText, installMarkdownRichText } from './adapters/codex/rich-text.mjs';
9
9
  import {
10
+ markdownExportAlias,
10
11
  loadNativeMarkdownTableActions,
11
12
  installMarkdownTableActions,
12
13
  } from './adapters/codex/table-actions.mjs';
@@ -32,6 +33,7 @@ export async function createPageScriptSource() {
32
33
  loadNativeMarkdownToc,
33
34
  installMarkdownToc,
34
35
  loadNativeMarkdownRenderer,
36
+ markdownExportAlias,
35
37
  loadNativeMarkdownTableActions,
36
38
  installMarkdownTableActions,
37
39
  loadNativeMarkdownRichText,
@@ -313,18 +313,18 @@
313
313
  padding-inline-start: calc(var(--mcx-list-indent) + var(--mcx-list-marker-width));
314
314
  }
315
315
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-alert-title {font-weight:var(--font-weight-semibold,600); color:var(--color-text-primary);}
316
- .cm-editor[data-minecodex-markdown-reading] .mcx-reading-rich-code {margin-block:16px; max-width:100%;}
316
+ .cm-editor[data-minecodex-markdown-reading] .mcx-reading-rich-code {padding-block:16px; max-width:100%;}
317
317
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-code-block {position:relative; min-width:0;}
318
318
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-code-block [data-block-actions] {top:4px; right:4px; transform:none; transition:opacity 120ms linear;}
319
319
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-code-block:focus-within [data-block-actions],
320
320
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-code-block:hover [data-block-actions] {opacity:1; pointer-events:auto;}
321
321
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-code-scroll {max-width:100%; scrollbar-width:thin;}
322
- .cm-editor[data-minecodex-markdown-reading] .mcx-reading-rich-html-block {margin-block:1em;}
322
+ .cm-editor[data-minecodex-markdown-reading] .mcx-reading-rich-html-block {padding-block:1em;}
323
323
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-rich mark {background:color-mix(in srgb, var(--color-content-yellow) 25%, transparent); color:inherit; border-radius:2px; padding-inline:2px;}
324
324
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-rich kbd {font-family:var(--font-mono,monospace); font-size:.9em; background:var(--color-token-bg-secondary); border:1px solid var(--color-border); border-radius:4px; padding:1px 4px;}
325
325
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-rich a,
326
326
  .cm-editor[data-minecodex-markdown-reading] :is(.mcx-reading-rich-footnote-ref,.mcx-reading-footnote-body) button {color:var(--color-text-accent, var(--color-token-text-link-foreground)); cursor:var(--cursor-interaction,pointer);}
327
- .cm-editor[data-minecodex-markdown-reading] .mcx-reading-rich-footnote-ref button {font:inherit; padding:0 2px; background:transparent; border:0;}
327
+ .cm-editor[data-minecodex-markdown-reading] .mcx-reading-rich-footnote-ref button {font:inherit; line-height:1; padding:0 2px; background:transparent; border:0;}
328
328
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-footnote-body {font-size:.9em; color:var(--color-text-secondary);}
329
329
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-footnote-body button {margin-inline-start:8px; background:transparent; border:0;}
330
330
  .cm-editor[data-minecodex-markdown-reading] .mcx-reading-definition-term {font-weight:var(--font-weight-semibold,600);}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minecodex",
3
- "version": "2.0.14",
3
+ "version": "2.0.15",
4
4
  "description": "Lightweight, local-first plugins for the Codex desktop app.",
5
5
  "license": "MIT",
6
6
  "type": "module",