mrmd-editor 0.7.1 → 0.8.0
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.
- package/package.json +3 -1
- package/src/commands.js +112 -4
- package/src/comment-syntax.js +364 -39
- package/src/config/handlers.js +1 -2
- package/src/config/schema.js +46 -4
- package/src/document-template.js +2236 -0
- package/src/frontmatter-updater.js +204 -74
- package/src/grammar.js +758 -0
- package/src/index.js +1074 -55
- package/src/keymap.js +11 -2
- package/src/markdown/block-decorations.js +108 -5
- package/src/markdown/facets.js +37 -0
- package/src/markdown/html-inline.js +9 -5
- package/src/markdown/index.js +13 -3
- package/src/markdown/inline-commands.js +256 -0
- package/src/markdown/inline-model.js +578 -0
- package/src/markdown/inline-state.js +103 -0
- package/src/markdown/renderer.js +219 -12
- package/src/markdown/styles.js +290 -3
- package/src/markdown/widgets/alert-title.js +10 -8
- package/src/markdown/widgets/frontmatter.js +0 -6
- package/src/markdown/widgets/index.js +1 -0
- package/src/markdown/widgets/list-marker.js +29 -0
- package/src/markdown/wysiwyg.js +1158 -0
- package/src/mrp-types.js +2 -0
- package/src/output-widget.js +532 -18
- package/src/page-view-pagination.js +127 -0
- package/src/runtime-lsp.js +1757 -150
- package/src/section-controls/commands.js +617 -0
- package/src/section-controls/index.js +63 -0
- package/src/section-controls/plugin.js +165 -0
- package/src/section-controls/widgets.js +936 -0
- package/src/shell/ai-menu.js +11 -0
- package/src/shell/components/context-panel.js +572 -0
- package/src/shell/components/status-bar.js +10 -2
- package/src/shell/layouts/studio.js +206 -14
- package/src/shell/orchestrator-client.js +69 -0
- package/src/spellcheck.js +166 -0
- package/src/tables/README.md +97 -0
- package/src/tables/commands/insert-linked-table.js +122 -0
- package/src/tables/commands/open-table-workspace.js +43 -0
- package/src/tables/index.js +24 -0
- package/src/tables/jobs/client.js +158 -0
- package/src/tables/parsing/anchors.js +82 -0
- package/src/tables/parsing/linked-table-blocks.js +61 -0
- package/src/tables/state/linked-table-state.js +68 -0
- package/src/tables/widgets/linked-table-source-banner.js +77 -0
- package/src/tables/widgets/linked-table-widget.js +256 -0
- package/src/tables/workspace/controller.js +616 -0
- package/src/term-pty-client.js +51 -2
- package/src/term-widget.js +43 -3
- package/src/widgets/theme-utils.js +24 -16
- package/src/widgets/theme.js +1015 -1
- package/src/runtime-codelens/detector.js +0 -279
- package/src/runtime-codelens/index.js +0 -76
- package/src/runtime-codelens/plugin.js +0 -142
- package/src/runtime-codelens/styles.js +0 -184
- package/src/runtime-codelens/widgets.js +0 -216
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section Controls Plugin (floating overlay)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ViewPlugin } from '@codemirror/view';
|
|
6
|
+
import { Facet } from '@codemirror/state';
|
|
7
|
+
import { syntaxTree } from '@codemirror/language';
|
|
8
|
+
import { getSelectionFormattingState } from '../markdown/inline-commands.js';
|
|
9
|
+
import { createSectionControlsDom, injectSectionControlsStyles } from './widgets.js';
|
|
10
|
+
|
|
11
|
+
export const sectionControlsFacet = Facet.define({
|
|
12
|
+
combine: (values) => values[0] || { enabled: true, showAi: true, showFormatting: true, mode: 'dots-click' },
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function getSectionAnchorPos(state) {
|
|
16
|
+
const head = state.selection.main.head;
|
|
17
|
+
const tree = syntaxTree(state);
|
|
18
|
+
let node = tree.resolveInner(head, -1);
|
|
19
|
+
|
|
20
|
+
while (node?.parent && node.parent.name !== 'Document') {
|
|
21
|
+
node = node.parent;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Fallback to current line end.
|
|
25
|
+
if (!node || node.name === 'Document') return state.doc.lineAt(head).to;
|
|
26
|
+
|
|
27
|
+
// End of top-level block (paragraph/list/table/code/etc.).
|
|
28
|
+
const safe = Math.max(node.from, Math.min(node.to - 1, state.doc.length));
|
|
29
|
+
return state.doc.lineAt(safe).to;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function createSectionControlsPlugin(editor) {
|
|
33
|
+
return ViewPlugin.fromClass(
|
|
34
|
+
class {
|
|
35
|
+
constructor(view) {
|
|
36
|
+
this.view = view;
|
|
37
|
+
this.config = view.state.facet(sectionControlsFacet);
|
|
38
|
+
this.dom = null;
|
|
39
|
+
this.measurePending = false;
|
|
40
|
+
|
|
41
|
+
injectSectionControlsStyles();
|
|
42
|
+
|
|
43
|
+
this.onWindowResize = () => this.scheduleReposition();
|
|
44
|
+
this.onScroll = () => this.scheduleReposition();
|
|
45
|
+
window.addEventListener('resize', this.onWindowResize);
|
|
46
|
+
this.view.scrollDOM.addEventListener('scroll', this.onScroll, { passive: true });
|
|
47
|
+
|
|
48
|
+
this.ensureDom();
|
|
49
|
+
this.scheduleReposition();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
ensureDom() {
|
|
53
|
+
if (this.dom) {
|
|
54
|
+
this.dom.remove();
|
|
55
|
+
this.dom = null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!this.config.enabled || (!this.config.showAi && !this.config.showFormatting)) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.dom = createSectionControlsDom(this.view, {
|
|
63
|
+
editor,
|
|
64
|
+
showAi: this.config.showAi,
|
|
65
|
+
showFormatting: this.config.showFormatting,
|
|
66
|
+
mode: this.config.mode,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
document.body.appendChild(this.dom);
|
|
70
|
+
this.updateFormattingState();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
updateFormattingState() {
|
|
74
|
+
if (!this.dom) return;
|
|
75
|
+
const formatting = getSelectionFormattingState(this.view);
|
|
76
|
+
const marks = ['bold', 'italic', 'underline', 'strikethrough', 'code'];
|
|
77
|
+
for (const mark of marks) {
|
|
78
|
+
const btn = this.dom.querySelector(`.cm-section-controls-btn.${mark}`);
|
|
79
|
+
if (!btn) continue;
|
|
80
|
+
const stateKey = mark === 'strikethrough' ? 'strikethrough' : mark;
|
|
81
|
+
btn.classList.toggle('is-active', !!formatting[stateKey]);
|
|
82
|
+
btn.classList.toggle('is-mixed', !!formatting.mixed?.[stateKey]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
scheduleReposition() {
|
|
87
|
+
if (!this.dom || this.measurePending) return;
|
|
88
|
+
|
|
89
|
+
this.measurePending = true;
|
|
90
|
+
|
|
91
|
+
this.view.requestMeasure({
|
|
92
|
+
read: (view) => {
|
|
93
|
+
this.measurePending = false;
|
|
94
|
+
if (!this.dom) return null;
|
|
95
|
+
|
|
96
|
+
const anchor = getSectionAnchorPos(view.state);
|
|
97
|
+
const coords = view.coordsAtPos(anchor);
|
|
98
|
+
if (!coords) return null;
|
|
99
|
+
|
|
100
|
+
const contentRect = view.contentDOM.getBoundingClientRect();
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
// Distance from right edge of viewport to right edge of content
|
|
104
|
+
rightOffset: window.innerWidth - contentRect.right,
|
|
105
|
+
bottom: coords.bottom,
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
write: (m) => {
|
|
109
|
+
if (!this.dom) return;
|
|
110
|
+
|
|
111
|
+
if (!m) {
|
|
112
|
+
this.dom.style.display = 'none';
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const top = Math.max(8, m.bottom + 6);
|
|
117
|
+
|
|
118
|
+
this.dom.style.display = 'block';
|
|
119
|
+
this.dom.style.left = 'auto';
|
|
120
|
+
this.dom.style.right = `${Math.max(8, m.rightOffset + 10)}px`;
|
|
121
|
+
this.dom.style.top = `${top}px`;
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
update(update) {
|
|
127
|
+
const newConfig = update.state.facet(sectionControlsFacet);
|
|
128
|
+
const configChanged = (
|
|
129
|
+
this.config.enabled !== newConfig.enabled ||
|
|
130
|
+
this.config.showAi !== newConfig.showAi ||
|
|
131
|
+
this.config.showFormatting !== newConfig.showFormatting ||
|
|
132
|
+
this.config.mode !== newConfig.mode
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (configChanged) {
|
|
136
|
+
this.config = newConfig;
|
|
137
|
+
this.ensureDom();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (configChanged || update.selectionSet || update.docChanged) {
|
|
141
|
+
this.updateFormattingState();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
configChanged ||
|
|
146
|
+
update.selectionSet ||
|
|
147
|
+
update.docChanged ||
|
|
148
|
+
update.viewportChanged ||
|
|
149
|
+
update.focusChanged
|
|
150
|
+
) {
|
|
151
|
+
this.scheduleReposition();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
destroy() {
|
|
156
|
+
window.removeEventListener('resize', this.onWindowResize);
|
|
157
|
+
this.view.scrollDOM.removeEventListener('scroll', this.onScroll);
|
|
158
|
+
if (this.dom) {
|
|
159
|
+
this.dom.remove();
|
|
160
|
+
this.dom = null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
}
|