more-compute 0.2.6__py3-none-any.whl → 0.3.0__py3-none-any.whl

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.
@@ -1,383 +0,0 @@
1
- /**
2
- * LEGACY COMPONENT - NO LONGER USED
3
- *
4
- * This component has been replaced by MonacoCell.tsx which provides:
5
- * - Modern Monaco Editor (VSCode engine)
6
- * - LSP support for Python autocomplete and hover
7
- * - Better performance and features
8
- *
9
- * Kept for reference only. Do not use in new code.
10
- */
11
-
12
- "use client";
13
-
14
- import React, { useRef, useEffect, useState } from "react";
15
- import { Cell as CellType } from "@/types/notebook";
16
- import CellOutput from "./output/CellOutput";
17
- import AddCellButton from "./cell/AddCellButton";
18
- import MarkdownRenderer from "./output/MarkdownRenderer";
19
- import CellButton from "./cell/CellButton";
20
- import {
21
- UpdateIcon,
22
- LinkBreak2Icon,
23
- PlayIcon,
24
- ChevronUpIcon,
25
- ChevronDownIcon,
26
- } from "@radix-ui/react-icons";
27
- import { Check, X } from "lucide-react";
28
- import { fixIndentation } from "@/lib/api";
29
-
30
- declare const CodeMirror: any;
31
-
32
- interface CellProps {
33
- cell: CellType;
34
- index: number;
35
- totalCells: number;
36
- isActive: boolean;
37
- isExecuting: boolean;
38
- onExecute: (index: number) => void;
39
- onInterrupt: (index: number) => void;
40
- onDelete: (index: number) => void;
41
- onUpdate: (index: number, source: string) => void;
42
- onSetActive: (index: number) => void;
43
- onAddCell: (type: "code" | "markdown", index: number) => void;
44
- onMoveUp: (index: number) => void;
45
- onMoveDown: (index: number) => void;
46
- }
47
-
48
- export const Cell: React.FC<CellProps> = ({
49
- cell,
50
- index,
51
- totalCells,
52
- isActive,
53
- isExecuting,
54
- onExecute,
55
- onDelete,
56
- onInterrupt,
57
- onUpdate,
58
- onSetActive,
59
- onAddCell,
60
- onMoveUp,
61
- onMoveDown,
62
- }) => {
63
- // ============================================================================
64
- // REFS
65
- // ============================================================================
66
- const editorRef = useRef<HTMLTextAreaElement>(null);
67
- const codeMirrorInstance = useRef<{
68
- setValue: (value: string) => void;
69
- toTextArea: () => void;
70
- getValue: () => string;
71
- } | null>(null);
72
- const wasEditingMarkdown = useRef(false);
73
- const indexRef = useRef<number>(index);
74
- const intervalRef = useRef<NodeJS.Timeout | null>(null);
75
-
76
- // ============================================================================
77
- // STATE
78
- // ============================================================================
79
- const [isEditing, setIsEditing] = useState(
80
- () => cell.cell_type === "code" || !cell.source?.trim()
81
- );
82
- const [elapsedLabel, setElapsedLabel] = useState<string | null>(
83
- cell.execution_time ?? null
84
- );
85
-
86
- // ============================================================================
87
- // UTILITIES
88
- // ============================================================================
89
- const formatMs = (ms: number): string => {
90
- if (ms < 1000) return `${ms.toFixed(0)}ms`;
91
- if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
92
- const totalSeconds = Math.floor(ms / 1000);
93
- const minutes = Math.floor(totalSeconds / 60);
94
- const seconds = totalSeconds % 60;
95
- return `${minutes}:${seconds.toString().padStart(2, "0")}s`;
96
- };
97
-
98
- const parseExecTime = (s?: string | null): number | null => {
99
- if (!s) return null;
100
- if (s.endsWith("ms")) return parseFloat(s.replace("ms", ""));
101
- if (s.endsWith("s")) return parseFloat(s.replace("s", "")) * 1000;
102
- return null;
103
- };
104
-
105
- // ============================================================================
106
- // COMPUTED VALUES
107
- // ============================================================================
108
- const isMarkdownWithContent =
109
- cell.cell_type === "markdown" && !isEditing && cell.source?.trim();
110
-
111
- // ============================================================================
112
- // HANDLERS
113
- // ============================================================================
114
- const handleExecute = () => {
115
- if (cell.cell_type === "markdown") {
116
- onExecute(indexRef.current);
117
- setIsEditing(false);
118
- } else {
119
- if (isExecuting) {
120
- onInterrupt(indexRef.current);
121
- } else {
122
- onExecute(indexRef.current);
123
- }
124
- }
125
- };
126
-
127
- const handleCellClick = () => {
128
- onSetActive(indexRef.current);
129
- if (cell.cell_type === "markdown") {
130
- setIsEditing(true);
131
- }
132
- };
133
-
134
- const handleFixIndentation = async () => {
135
- try {
136
- const fixedCode = await fixIndentation(cell.source);
137
- onUpdate(indexRef.current, fixedCode);
138
-
139
- if (codeMirrorInstance.current) {
140
- codeMirrorInstance.current.setValue(fixedCode);
141
- }
142
- } catch (err) {
143
- console.error("Failed to fix indentation:", err);
144
- }
145
- };
146
-
147
- // ============================================================================
148
- // EFFECTS
149
- // ============================================================================
150
-
151
- // Keep indexRef in sync
152
- useEffect(() => {
153
- indexRef.current = index;
154
- }, [index]);
155
-
156
- // Execution timer
157
- useEffect(() => {
158
- if (isExecuting) {
159
- const start = Date.now();
160
- setElapsedLabel("0ms");
161
- if (intervalRef.current) clearInterval(intervalRef.current);
162
- intervalRef.current = setInterval(() => {
163
- setElapsedLabel(formatMs(Date.now() - start));
164
- }, 100);
165
- } else {
166
- if (intervalRef.current) {
167
- clearInterval(intervalRef.current);
168
- intervalRef.current = null;
169
- }
170
- const ms = parseExecTime(cell.execution_time as any);
171
- if (ms != null) setElapsedLabel(formatMs(ms));
172
- }
173
-
174
- return () => {
175
- if (intervalRef.current) {
176
- clearInterval(intervalRef.current);
177
- intervalRef.current = null;
178
- }
179
- };
180
- }, [isExecuting, cell.execution_time]);
181
-
182
- // Track when user is editing markdown (for auto-save on click away)
183
- useEffect(() => {
184
- if (isActive && cell.cell_type === "markdown" && isEditing) {
185
- wasEditingMarkdown.current = true;
186
- }
187
- }, [isActive, cell.cell_type]);
188
-
189
- // Auto-save markdown when user clicks away
190
- useEffect(() => {
191
- if (
192
- !isActive &&
193
- wasEditingMarkdown.current &&
194
- cell.cell_type === "markdown"
195
- ) {
196
- if (cell.source?.trim()) {
197
- onExecute(indexRef.current);
198
- setIsEditing(false);
199
- }
200
- wasEditingMarkdown.current = false;
201
- }
202
- }, [isActive, cell.cell_type]);
203
-
204
- // CodeMirror editor initialization and cleanup
205
- useEffect(() => {
206
- if (isEditing) {
207
- if (
208
- !codeMirrorInstance.current &&
209
- editorRef.current &&
210
- typeof CodeMirror !== "undefined"
211
- ) {
212
- const editor = CodeMirror.fromTextArea(editorRef.current, {
213
- mode: cell.cell_type === "code" ? "python" : "text/plain",
214
- lineNumbers: cell.cell_type === "code",
215
- theme: "default",
216
- lineWrapping: true,
217
- placeholder:
218
- cell.cell_type === "code" ? "Enter code..." : "Enter markdown...",
219
- });
220
- codeMirrorInstance.current = editor;
221
-
222
- editor.on("change", (instance: any) =>
223
- onUpdate(indexRef.current, instance.getValue())
224
- );
225
- editor.on("focus", () => onSetActive(indexRef.current));
226
- editor.on("blur", () => {
227
- if (cell.cell_type === "markdown") {
228
- if (cell.source?.trim()) {
229
- // Auto-save on blur
230
- onExecute(indexRef.current);
231
- setIsEditing(false);
232
- }
233
- // If empty, stay in editing mode but mark as no longer editing
234
- wasEditingMarkdown.current = false;
235
- }
236
- });
237
- editor.on("keydown", (instance: any, event: KeyboardEvent) => {
238
- if (event.shiftKey && event.key === "Enter") {
239
- event.preventDefault();
240
- handleExecute();
241
- }
242
- });
243
-
244
- if (editor.getValue() !== cell.source) {
245
- editor.setValue(cell.source);
246
- }
247
- }
248
- } else {
249
- if (codeMirrorInstance.current) {
250
- codeMirrorInstance.current.toTextArea();
251
- codeMirrorInstance.current = null;
252
- }
253
- }
254
- }, [isEditing, cell.source]);
255
-
256
- // ============================================================================
257
- // RENDER
258
- // ============================================================================
259
- return (
260
- <div className="cell-wrapper">
261
- {/* Status Indicator */}
262
- {!isMarkdownWithContent && (
263
- <div className="cell-status-indicator">
264
- <span className="status-indicator">
265
- <span className="status-bracket">[</span>
266
- {isExecuting ? (
267
- <UpdateIcon className="w-1 h-1" />
268
- ) : cell.error ? (
269
- <X size={14} color="#dc2626" />
270
- ) : cell.execution_count != null ? (
271
- <Check size={14} color="#16a34a" />
272
- ) : (
273
- <span
274
- style={{
275
- width: "14px",
276
- height: "14px",
277
- display: "inline-block",
278
- }}
279
- ></span>
280
- )}
281
- <span className="status-bracket">]</span>
282
- </span>
283
- {elapsedLabel && (
284
- <span className="status-timer" title="Execution time">
285
- {elapsedLabel}
286
- </span>
287
- )}
288
- </div>
289
- )}
290
-
291
- {/* Add Cell Above Button */}
292
- <div className="add-cell-line add-line-above">
293
- <AddCellButton onAddCell={(type) => onAddCell(type, indexRef.current)} />
294
- </div>
295
-
296
- {/* Main Cell Container */}
297
- <div
298
- className={`cell ${isActive ? "active" : ""} ${isExecuting ? "executing" : ""} ${isMarkdownWithContent ? "markdown-display-mode" : ""}`}
299
- data-cell-index={index}
300
- >
301
- {/* Hover Controls */}
302
- {!isMarkdownWithContent && (
303
- <div className="cell-hover-controls">
304
- <div className="cell-actions-right">
305
- <CellButton
306
- icon={<PlayIcon className="w-6 h-6" />}
307
- onClick={(e) => {
308
- e.stopPropagation();
309
- handleExecute();
310
- }}
311
- title={isExecuting ? "Stop execution" : "Run cell"}
312
- isLoading={isExecuting}
313
- />
314
- <CellButton
315
- icon={<ChevronUpIcon className="w-6 h-6" />}
316
- onClick={(e) => {
317
- e.stopPropagation();
318
- onMoveUp(indexRef.current);
319
- }}
320
- title="Move cell up"
321
- disabled={index === 0}
322
- />
323
- <CellButton
324
- icon={<ChevronDownIcon className="w-6 h-6" />}
325
- onClick={(e) => {
326
- e.stopPropagation();
327
- onMoveDown(indexRef.current);
328
- }}
329
- title="Move cell down"
330
- disabled={index === totalCells - 1}
331
- />
332
- <CellButton
333
- icon={<LinkBreak2Icon className="w-5 h-5" />}
334
- onClick={(e) => {
335
- e.stopPropagation();
336
- onDelete(indexRef.current);
337
- }}
338
- title="Delete cell"
339
- />
340
- </div>
341
- </div>
342
- )}
343
-
344
- {/* Cell Content */}
345
- <div
346
- className={`cell-content ${isMarkdownWithContent ? "cursor-pointer" : ""}`}
347
- onClick={handleCellClick}
348
- >
349
- <div className="cell-input">
350
- {isEditing || cell.cell_type === "code" ? (
351
- <div
352
- className={`cell-editor-container ${cell.cell_type === "markdown" ? "markdown-editor-container" : "code-editor-container"}`}
353
- >
354
- <textarea
355
- ref={editorRef}
356
- defaultValue={cell.source}
357
- className={`cell-editor ${cell.cell_type === "markdown" ? "markdown-editor" : "code-editor"}`}
358
- />
359
- </div>
360
- ) : (
361
- <MarkdownRenderer
362
- source={cell.source}
363
- onClick={() => setIsEditing(true)}
364
- />
365
- )}
366
- </div>
367
- <CellOutput
368
- outputs={cell.outputs}
369
- error={cell.error}
370
- onFixIndentation={handleFixIndentation}
371
- />
372
- </div>
373
- </div>
374
-
375
- {/* Add Cell Below Button */}
376
- <div className="add-cell-line add-line-below">
377
- <AddCellButton
378
- onAddCell={(type) => onAddCell(type, indexRef.current + 1)}
379
- />
380
- </div>
381
- </div>
382
- );
383
- };