vzcode 0.70.0 → 0.71.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/dist/assets/{index-DOd2vdTJ.css → index-B4YHcAhs.css} +1 -1
- package/dist/assets/{index-Bfl2hCW9.js → index-HJAv0wn0.js} +46 -46
- package/dist/index.html +2 -2
- package/package.json +12 -12
- package/src/client/AIAssist/AIAssistWidget/index.tsx +10 -3
- package/src/client/AIAssist/AIAssistWidget/style.scss +4 -2
- package/src/client/AIAssist/index.ts +0 -1
- package/src/client/CodeEditor/index.tsx +6 -5
- package/src/client/Icons/PlaySVG.tsx +16 -0
- package/src/client/Icons/index.tsx +1 -0
- package/src/client/RunCodeWidget/index.tsx +53 -0
- package/src/client/RunCodeWidget/style.scss +7 -0
- package/src/client/TabList/style.scss +4 -4
- package/src/client/VZCodeContext.tsx +14 -8
- package/src/client/VZMiddle.tsx +2 -0
- package/src/client/shouldTriggerRun.ts +0 -2
- package/src/client/useKeyboardShortcuts.ts +54 -16
- package/src/client/usePrettier/index.ts +34 -102
- package/src/client/useRunCode.tsx +28 -0
- package/src/server/computeInitialDocument.js +2 -1
- package/src/server/index.js +1 -49
- package/src/types.ts +10 -0
package/dist/index.html
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
|
|
21
21
|
rel="stylesheet"
|
|
22
22
|
/>
|
|
23
|
-
<script type="module" crossorigin src="/assets/index-
|
|
24
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
23
|
+
<script type="module" crossorigin src="/assets/index-HJAv0wn0.js"></script>
|
|
24
|
+
<link rel="stylesheet" crossorigin href="/assets/index-B4YHcAhs.css">
|
|
25
25
|
</head>
|
|
26
26
|
<body>
|
|
27
27
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vzcode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.71.0",
|
|
4
4
|
"description": "Multiplayer code editor system",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -79,15 +79,15 @@
|
|
|
79
79
|
"@replit/codemirror-vscode-keymap": "^6.0.2",
|
|
80
80
|
"@teamwork/websocket-json-stream": "^2.0.0",
|
|
81
81
|
"@typescript/vfs": "^1.5.0",
|
|
82
|
-
"@uiw/codemirror-theme-abcdef": "^4.21.
|
|
83
|
-
"@uiw/codemirror-theme-dracula": "^4.21.
|
|
84
|
-
"@uiw/codemirror-theme-eclipse": "^4.21.
|
|
85
|
-
"@uiw/codemirror-theme-github": "^4.21.
|
|
86
|
-
"@uiw/codemirror-theme-material": "^4.21.
|
|
87
|
-
"@uiw/codemirror-theme-nord": "^4.21.
|
|
88
|
-
"@uiw/codemirror-theme-okaidia": "^4.21.
|
|
89
|
-
"@uiw/codemirror-theme-xcode": "^4.21.
|
|
90
|
-
"@uiw/codemirror-themes": "^4.21.
|
|
82
|
+
"@uiw/codemirror-theme-abcdef": "^4.21.22",
|
|
83
|
+
"@uiw/codemirror-theme-dracula": "^4.21.22",
|
|
84
|
+
"@uiw/codemirror-theme-eclipse": "^4.21.22",
|
|
85
|
+
"@uiw/codemirror-theme-github": "^4.21.22",
|
|
86
|
+
"@uiw/codemirror-theme-material": "^4.21.22",
|
|
87
|
+
"@uiw/codemirror-theme-nord": "^4.21.22",
|
|
88
|
+
"@uiw/codemirror-theme-okaidia": "^4.21.22",
|
|
89
|
+
"@uiw/codemirror-theme-xcode": "^4.21.22",
|
|
90
|
+
"@uiw/codemirror-themes": "^4.21.22",
|
|
91
91
|
"body-parser": "^1.20.2",
|
|
92
92
|
"codemirror": "^6.0.1",
|
|
93
93
|
"codemirror-ot": "^4.2.0",
|
|
@@ -108,11 +108,11 @@
|
|
|
108
108
|
"react-router-dom": "^6.22.1",
|
|
109
109
|
"sharedb": "^4.1.2",
|
|
110
110
|
"sharedb-client-browser": "^4.4.0",
|
|
111
|
-
"vizhub-ui": "^3.
|
|
111
|
+
"vizhub-ui": "^3.20.0",
|
|
112
112
|
"ws": "^8.16.0"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
115
|
-
"@types/react": "^18.2.
|
|
115
|
+
"@types/react": "^18.2.56",
|
|
116
116
|
"@types/react-dom": "^18.2.19",
|
|
117
117
|
"@vitejs/plugin-react": "^4.2.1",
|
|
118
118
|
"concurrently": "^8.2.2",
|
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
RequestId,
|
|
12
12
|
generateRequestId,
|
|
13
13
|
} from '../../generateRequestId';
|
|
14
|
-
import { SparklesSVG
|
|
14
|
+
import { SparklesSVG } from '../../Icons';
|
|
15
15
|
import { startAIAssist } from '../startAIAssist';
|
|
16
|
-
import './style.scss';
|
|
17
16
|
import { Spinner } from '../Spinner';
|
|
18
17
|
import { VZCodeContext } from '../../VZCodeContext';
|
|
18
|
+
import './style.scss';
|
|
19
19
|
|
|
20
20
|
const enableStopGeneration = false;
|
|
21
21
|
|
|
@@ -45,7 +45,8 @@ export const AIAssistWidget = ({
|
|
|
45
45
|
const [aiStreamId, setAiStreamId] =
|
|
46
46
|
useState<RequestId | null>(null);
|
|
47
47
|
|
|
48
|
-
const { runPrettierRef } =
|
|
48
|
+
const { runPrettierRef, runCodeRef } =
|
|
49
|
+
useContext(VZCodeContext);
|
|
49
50
|
|
|
50
51
|
const handleClick = useCallback(async () => {
|
|
51
52
|
const isCurrentlyGenerationg = aiStreamId !== null;
|
|
@@ -72,6 +73,12 @@ export const AIAssistWidget = ({
|
|
|
72
73
|
runPrettier();
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
// Run the code after the AI Assist.
|
|
77
|
+
const runCode = runCodeRef.current;
|
|
78
|
+
if (runCode !== null) {
|
|
79
|
+
runCode();
|
|
80
|
+
}
|
|
81
|
+
|
|
75
82
|
// Handles the case that the user has started,
|
|
76
83
|
// stopped, and started again before the first request
|
|
77
84
|
// has finished, bu comparing the current stream ID
|
|
@@ -80,13 +80,14 @@ export const CodeEditor = ({
|
|
|
80
80
|
clearTimeout(interactTimeoutRef.current);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
// Set `isInteracting:
|
|
83
|
+
// Set `isInteracting: undefined` after a delay.
|
|
84
84
|
interactTimeoutRef.current = setTimeout(() => {
|
|
85
85
|
interactTimeoutRef.current = null;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
|
|
87
|
+
// This logic deletes the `isInteracting` property from the document.
|
|
88
|
+
submitOperation(
|
|
89
|
+
({ isInteracting, ...newDocument }) => newDocument,
|
|
90
|
+
);
|
|
90
91
|
}, 800);
|
|
91
92
|
}, [submitOperation]);
|
|
92
93
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const PlaySVG = () => (
|
|
2
|
+
<svg
|
|
3
|
+
width="24"
|
|
4
|
+
height="24"
|
|
5
|
+
fill="none"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
strokeWidth={1.5}
|
|
8
|
+
stroke="currentColor"
|
|
9
|
+
>
|
|
10
|
+
<path
|
|
11
|
+
strokeLinecap="round"
|
|
12
|
+
strokeLinejoin="round"
|
|
13
|
+
d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z"
|
|
14
|
+
/>
|
|
15
|
+
</svg>
|
|
16
|
+
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useCallback, useContext } from 'react';
|
|
2
|
+
import { PlaySVG } from '../Icons';
|
|
3
|
+
import { VZCodeContext } from '../VZCodeContext';
|
|
4
|
+
import { OverlayTrigger, Tooltip } from '../bootstrap';
|
|
5
|
+
import './style.scss';
|
|
6
|
+
|
|
7
|
+
export const RunCodeWidget = ({
|
|
8
|
+
runCodeWidgetTooltipText = (
|
|
9
|
+
<>
|
|
10
|
+
<strong>Run Code</strong>
|
|
11
|
+
<div>(Shift + Enter or Ctrl + s)</div>
|
|
12
|
+
</>
|
|
13
|
+
),
|
|
14
|
+
}: {
|
|
15
|
+
runCodeWidgetTooltipText?: JSX.Element;
|
|
16
|
+
}) => {
|
|
17
|
+
const { runCodeRef, runPrettierRef } =
|
|
18
|
+
useContext(VZCodeContext);
|
|
19
|
+
|
|
20
|
+
const handleClick = useCallback(() => {
|
|
21
|
+
// Run Prettier
|
|
22
|
+
const runPrettier = runPrettierRef.current;
|
|
23
|
+
if (runPrettier !== null) {
|
|
24
|
+
runPrettier();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Run the code
|
|
28
|
+
const runCode = runCodeRef.current;
|
|
29
|
+
if (runCode !== null) {
|
|
30
|
+
runCode();
|
|
31
|
+
}
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className="vz-code-run-code-widget">
|
|
36
|
+
<OverlayTrigger
|
|
37
|
+
placement="left"
|
|
38
|
+
overlay={
|
|
39
|
+
<Tooltip id="run-code-widget-tooltip">
|
|
40
|
+
{runCodeWidgetTooltipText}
|
|
41
|
+
</Tooltip>
|
|
42
|
+
}
|
|
43
|
+
>
|
|
44
|
+
<i
|
|
45
|
+
className="icon-button icon-button-dark"
|
|
46
|
+
onClick={handleClick}
|
|
47
|
+
>
|
|
48
|
+
<PlaySVG />
|
|
49
|
+
</i>
|
|
50
|
+
</OverlayTrigger>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
align-items: center;
|
|
13
13
|
display: flex;
|
|
14
14
|
gap: 8px;
|
|
15
|
-
padding:
|
|
16
|
-
border-top-left-radius:
|
|
17
|
-
border-top-right-radius:
|
|
18
|
-
margin-top:
|
|
15
|
+
padding: 6px 6px 6px 16px;
|
|
16
|
+
border-top-left-radius: 8px;
|
|
17
|
+
border-top-right-radius: 8px;
|
|
18
|
+
margin-top: 6px;
|
|
19
19
|
margin-left: 2px;
|
|
20
20
|
margin-right: 2px;
|
|
21
21
|
cursor: pointer;
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
Files,
|
|
9
9
|
ShareDBDoc,
|
|
10
|
+
SubmitOperation,
|
|
10
11
|
Username,
|
|
11
12
|
VZCodeContent,
|
|
12
13
|
} from '../types';
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
} from './useEditorCache';
|
|
32
33
|
import { useURLSync } from './useURLSync';
|
|
33
34
|
import { useKeyboardShortcuts } from './useKeyboardShortcuts';
|
|
35
|
+
import { useRunCode } from './useRunCode';
|
|
34
36
|
|
|
35
37
|
// This context centralizes all the "smart" logic
|
|
36
38
|
// to do with the application state. This includes
|
|
@@ -98,6 +100,7 @@ export type VZCodeContextValue = {
|
|
|
98
100
|
runPrettierRef: React.MutableRefObject<
|
|
99
101
|
null | (() => void)
|
|
100
102
|
>;
|
|
103
|
+
runCodeRef: React.MutableRefObject<null | (() => void)>;
|
|
101
104
|
};
|
|
102
105
|
|
|
103
106
|
export const VZCodeProvider = ({
|
|
@@ -115,9 +118,7 @@ export const VZCodeProvider = ({
|
|
|
115
118
|
}: {
|
|
116
119
|
content: VZCodeContent;
|
|
117
120
|
shareDBDoc: ShareDBDoc<VZCodeContent>;
|
|
118
|
-
submitOperation:
|
|
119
|
-
next: (content: VZCodeContent) => VZCodeContent,
|
|
120
|
-
) => void;
|
|
121
|
+
submitOperation: SubmitOperation;
|
|
121
122
|
localPresence: any;
|
|
122
123
|
docPresence: any;
|
|
123
124
|
prettierWorker: Worker;
|
|
@@ -143,6 +144,8 @@ export const VZCodeProvider = ({
|
|
|
143
144
|
enableManualPretter,
|
|
144
145
|
});
|
|
145
146
|
|
|
147
|
+
const runCodeRef = useRunCode(submitOperation);
|
|
148
|
+
|
|
146
149
|
// The error message shows either:
|
|
147
150
|
// * `prettierError` - errors from Prettier, client-side only
|
|
148
151
|
// * `codeError` - errors from an external source, such as
|
|
@@ -247,19 +250,21 @@ export const VZCodeProvider = ({
|
|
|
247
250
|
[createFile, setIsCreateFileModalOpen],
|
|
248
251
|
);
|
|
249
252
|
|
|
253
|
+
// Isolate the files object from the document.
|
|
254
|
+
const files: Files | null = content
|
|
255
|
+
? content.files
|
|
256
|
+
: null;
|
|
257
|
+
|
|
250
258
|
useKeyboardShortcuts({
|
|
251
259
|
closeTabs,
|
|
252
260
|
activeFileId,
|
|
253
261
|
handleOpenCreateFileModal,
|
|
254
262
|
setActiveFileLeft,
|
|
255
263
|
setActiveFileRight,
|
|
264
|
+
runPrettierRef,
|
|
265
|
+
runCodeRef,
|
|
256
266
|
});
|
|
257
267
|
|
|
258
|
-
// Isolate the files object from the document.
|
|
259
|
-
const files: Files | null = content
|
|
260
|
-
? content.files
|
|
261
|
-
: null;
|
|
262
|
-
|
|
263
268
|
// The value provided by this context.
|
|
264
269
|
const value: VZCodeContextValue = {
|
|
265
270
|
content,
|
|
@@ -309,6 +314,7 @@ export const VZCodeProvider = ({
|
|
|
309
314
|
handleCloseCreateFileModal,
|
|
310
315
|
handleCreateFileClick,
|
|
311
316
|
runPrettierRef,
|
|
317
|
+
runCodeRef,
|
|
312
318
|
};
|
|
313
319
|
|
|
314
320
|
return (
|
package/src/client/VZMiddle.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { CodeErrorOverlay } from './CodeErrorOverlay';
|
|
|
6
6
|
import { PresenceNotifications } from './PresenceNotifications';
|
|
7
7
|
import { AIAssistWidget } from './AIAssist/AIAssistWidget';
|
|
8
8
|
import { VZCodeContext } from './VZCodeContext';
|
|
9
|
+
import { RunCodeWidget } from './RunCodeWidget';
|
|
9
10
|
|
|
10
11
|
// The middle portion of the VZCode environment, containing:
|
|
11
12
|
// * The list of tabs at the top
|
|
@@ -106,6 +107,7 @@ export const VZMiddle = ({
|
|
|
106
107
|
aiAssistClickOverride={aiAssistClickOverride}
|
|
107
108
|
/>
|
|
108
109
|
) : null}
|
|
110
|
+
<RunCodeWidget />
|
|
109
111
|
<CodeErrorOverlay
|
|
110
112
|
errorMessage={errorMessage}
|
|
111
113
|
content={content}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// This module is responsible for checking
|
|
2
2
|
// keyboard events and determining whether
|
|
3
3
|
// a run should be triggered or not.
|
|
4
|
-
//
|
|
5
|
-
// The most common case is when the us
|
|
6
4
|
export const shouldTriggerRun = (event: KeyboardEvent) => {
|
|
7
5
|
const isMac = /Mac|iMac|MacBook/i.test(
|
|
8
6
|
navigator.userAgent,
|
|
@@ -1,41 +1,73 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useContext, useEffect } from 'react';
|
|
2
|
+
import { shouldTriggerRun } from './shouldTriggerRun';
|
|
3
|
+
import { VZCodeContext } from './VZCodeContext';
|
|
2
4
|
|
|
5
|
+
// This module implements the keyboard shortcuts
|
|
6
|
+
// for the VZCode editor.
|
|
7
|
+
// These include:
|
|
8
|
+
// * Alt-w: Close the current tab
|
|
9
|
+
// * Alt-n: Open the create file modal
|
|
10
|
+
// * Alt-PageUp: Change the active tab to the previous one
|
|
11
|
+
// * Alt-PageDown: Change the active tab to the next one
|
|
12
|
+
// * Ctrl-s or Shift-Enter: Run the code and format it with Prettier
|
|
3
13
|
export const useKeyboardShortcuts = ({
|
|
4
14
|
closeTabs,
|
|
5
15
|
activeFileId,
|
|
6
16
|
handleOpenCreateFileModal,
|
|
7
17
|
setActiveFileLeft,
|
|
8
18
|
setActiveFileRight,
|
|
19
|
+
runPrettierRef,
|
|
20
|
+
runCodeRef,
|
|
9
21
|
}) => {
|
|
10
|
-
|
|
11
|
-
(event: KeyboardEvent) => {
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const handleKeyPress = (event: KeyboardEvent) => {
|
|
24
|
+
if (shouldTriggerRun(event)) {
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
|
|
27
|
+
// Run Prettier
|
|
28
|
+
const runPrettier = runPrettierRef.current;
|
|
29
|
+
if (runPrettier !== null) {
|
|
30
|
+
runPrettier();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Run the code
|
|
34
|
+
const runCode = runCodeRef.current;
|
|
35
|
+
if (runCode !== null) {
|
|
36
|
+
runCode();
|
|
37
|
+
}
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
12
41
|
if (event.altKey === true) {
|
|
42
|
+
// Alt-w: Close the current tab
|
|
13
43
|
if (event.key === 'w') {
|
|
44
|
+
// TODO clean this up so we can remove `activeFileId`
|
|
45
|
+
// as a dependency
|
|
46
|
+
// TODO closeActiveTab()
|
|
14
47
|
closeTabs([activeFileId]);
|
|
48
|
+
return;
|
|
15
49
|
}
|
|
50
|
+
|
|
51
|
+
// Alt-n: Open the create file modal
|
|
16
52
|
if (event.key === 'n') {
|
|
17
53
|
handleOpenCreateFileModal();
|
|
54
|
+
return;
|
|
18
55
|
}
|
|
56
|
+
|
|
57
|
+
// Alt-PageUp: Change the active tab to the previous one
|
|
19
58
|
if (event.key === 'PageUp') {
|
|
20
|
-
// Change the active tab to the previous one
|
|
21
59
|
setActiveFileLeft();
|
|
60
|
+
return;
|
|
22
61
|
}
|
|
62
|
+
|
|
63
|
+
// Alt-PageDown: Change the active tab to the next one
|
|
23
64
|
if (event.key === 'PageDown') {
|
|
24
|
-
// Change the active tab to the next one
|
|
25
65
|
setActiveFileRight();
|
|
66
|
+
return;
|
|
26
67
|
}
|
|
27
68
|
}
|
|
28
|
-
}
|
|
29
|
-
[
|
|
30
|
-
handleOpenCreateFileModal,
|
|
31
|
-
closeTabs,
|
|
32
|
-
activeFileId,
|
|
33
|
-
setActiveFileLeft,
|
|
34
|
-
setActiveFileRight,
|
|
35
|
-
],
|
|
36
|
-
);
|
|
69
|
+
};
|
|
37
70
|
|
|
38
|
-
useEffect(() => {
|
|
39
71
|
document.addEventListener('keydown', handleKeyPress);
|
|
40
72
|
return () => {
|
|
41
73
|
document.removeEventListener(
|
|
@@ -43,5 +75,11 @@ export const useKeyboardShortcuts = ({
|
|
|
43
75
|
handleKeyPress,
|
|
44
76
|
);
|
|
45
77
|
};
|
|
46
|
-
}, [
|
|
78
|
+
}, [
|
|
79
|
+
handleOpenCreateFileModal,
|
|
80
|
+
closeTabs,
|
|
81
|
+
activeFileId,
|
|
82
|
+
setActiveFileLeft,
|
|
83
|
+
setActiveFileRight,
|
|
84
|
+
]);
|
|
47
85
|
};
|
|
@@ -31,14 +31,12 @@ export const usePrettier = ({
|
|
|
31
31
|
shareDBDoc,
|
|
32
32
|
submitOperation,
|
|
33
33
|
prettierWorker,
|
|
34
|
-
enableManualPretter,
|
|
35
34
|
}: {
|
|
36
35
|
shareDBDoc: ShareDBDoc<VZCodeContent> | null;
|
|
37
36
|
submitOperation: (
|
|
38
37
|
next: (content: VZCodeContent) => VZCodeContent,
|
|
39
38
|
) => void;
|
|
40
39
|
prettierWorker: Worker;
|
|
41
|
-
enableManualPretter: boolean;
|
|
42
40
|
}) => {
|
|
43
41
|
// The set of files that have been modified
|
|
44
42
|
// since the last Prettier run.
|
|
@@ -139,114 +137,48 @@ export const usePrettier = ({
|
|
|
139
137
|
};
|
|
140
138
|
runPrettierRef.current = runPrettier;
|
|
141
139
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
window.addEventListener('keydown', debouncePrettier);
|
|
169
|
-
}
|
|
140
|
+
const handleOpBatch = (op: JSONOp) => {
|
|
141
|
+
// Only act on changes coming from the client
|
|
142
|
+
// OR changes coming from the AI Assist that we
|
|
143
|
+
// if (isLocal) {
|
|
144
|
+
// If the op is coming from Prettier itself,
|
|
145
|
+
// then do nothing.
|
|
146
|
+
if (isApplyingOpRef.current) {
|
|
147
|
+
// console.log('ignoring op from Prettier');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Check if the path of this op is the text content of a file
|
|
152
|
+
if (
|
|
153
|
+
op &&
|
|
154
|
+
op.length === 4 &&
|
|
155
|
+
op[0] === 'files' &&
|
|
156
|
+
typeof op[1] === 'string' &&
|
|
157
|
+
op[2] === 'text'
|
|
158
|
+
) {
|
|
159
|
+
// Get the file id
|
|
160
|
+
const fileId: FileId = op[1];
|
|
161
|
+
|
|
162
|
+
// Add the file id to the set of dirty files
|
|
163
|
+
dirtyFilesRef.current.add(fileId);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
170
166
|
|
|
171
167
|
// Listen for changes
|
|
172
|
-
shareDBDoc.on(
|
|
173
|
-
'op batch',
|
|
174
|
-
(op: JSONOp, isLocal: boolean) => {
|
|
175
|
-
// Only act on changes coming from the client
|
|
176
|
-
// OR changes coming from the AI Assist that we
|
|
177
|
-
// if (isLocal) {
|
|
178
|
-
// If the op is coming from Prettier itself,
|
|
179
|
-
// then do nothing.
|
|
180
|
-
if (isApplyingOpRef.current) {
|
|
181
|
-
// console.log('ignoring op from Prettier');
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Example op that we want to act on:
|
|
186
|
-
// op [
|
|
187
|
-
// "files",
|
|
188
|
-
// "2514857669",
|
|
189
|
-
// "text",
|
|
190
|
-
// {
|
|
191
|
-
// "es": [
|
|
192
|
-
// 18,
|
|
193
|
-
// "d"
|
|
194
|
-
// ]
|
|
195
|
-
// }
|
|
196
|
-
// ]
|
|
197
|
-
|
|
198
|
-
// Check if the path of this op is the text content of a file
|
|
199
|
-
if (
|
|
200
|
-
op &&
|
|
201
|
-
op.length === 4 &&
|
|
202
|
-
op[0] === 'files' &&
|
|
203
|
-
typeof op[1] === 'string' &&
|
|
204
|
-
op[2] === 'text'
|
|
205
|
-
) {
|
|
206
|
-
// Get the file id
|
|
207
|
-
const fileId: FileId = op[1];
|
|
208
|
-
|
|
209
|
-
// Add the file id to the set of dirty files
|
|
210
|
-
dirtyFilesRef.current.add(fileId);
|
|
211
|
-
|
|
212
|
-
// Debounce running Prettier
|
|
213
|
-
if (!enableManualPretter) {
|
|
214
|
-
debouncePrettier();
|
|
215
|
-
}
|
|
216
|
-
// console.log('Op is for file', fileId);
|
|
217
|
-
}
|
|
218
|
-
// } else {
|
|
219
|
-
// // console.log('ignoring op from remote', op, isLocal);
|
|
220
|
-
// }
|
|
221
|
-
},
|
|
222
|
-
);
|
|
168
|
+
shareDBDoc.on('op batch', handleOpBatch);
|
|
223
169
|
|
|
224
|
-
//
|
|
170
|
+
// Clean up the event listeners
|
|
225
171
|
return () => {
|
|
226
|
-
// Remove the event listener
|
|
227
172
|
prettierWorker.removeEventListener(
|
|
228
173
|
'message',
|
|
229
174
|
handleMessage,
|
|
230
175
|
);
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
'keydown',
|
|
234
|
-
handleKeyDown,
|
|
235
|
-
);
|
|
236
|
-
} else {
|
|
237
|
-
window.removeEventListener(
|
|
238
|
-
'keydown',
|
|
239
|
-
debouncePrettier,
|
|
240
|
-
);
|
|
241
|
-
window.removeEventListener(
|
|
242
|
-
'mousemove',
|
|
243
|
-
debouncePrettier,
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
// Clear the timeout
|
|
247
|
-
clearTimeout(debounceTimeout);
|
|
248
|
-
}
|
|
176
|
+
|
|
177
|
+
shareDBDoc.removeListener('op batch', handleOpBatch);
|
|
249
178
|
};
|
|
250
179
|
}, [shareDBDoc]);
|
|
251
|
-
|
|
180
|
+
|
|
181
|
+
// Return the errors and run prettier function ref
|
|
182
|
+
// for use elsewhere.
|
|
183
|
+
return { prettierError, runPrettierRef };
|
|
252
184
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { SubmitOperation, VZCodeContent } from '../types';
|
|
3
|
+
|
|
4
|
+
// Runs the code by flashing `isInteracting` to `true`.
|
|
5
|
+
export const useRunCode = (
|
|
6
|
+
submitOperation: SubmitOperation,
|
|
7
|
+
) => {
|
|
8
|
+
const runCodeRef = useRef(null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const runCode = () => {
|
|
11
|
+
submitOperation((content: VZCodeContent) => ({
|
|
12
|
+
...content,
|
|
13
|
+
isInteracting: true,
|
|
14
|
+
}));
|
|
15
|
+
setTimeout(() => {
|
|
16
|
+
// This somewhat cryptic logic
|
|
17
|
+
// deletes the `isInteracting` property
|
|
18
|
+
// from the document.
|
|
19
|
+
submitOperation(
|
|
20
|
+
({ isInteracting, ...newDocument }) =>
|
|
21
|
+
newDocument,
|
|
22
|
+
);
|
|
23
|
+
}, 0);
|
|
24
|
+
};
|
|
25
|
+
runCodeRef.current = runCode;
|
|
26
|
+
}, [submitOperation]);
|
|
27
|
+
return runCodeRef;
|
|
28
|
+
};
|
|
@@ -87,7 +87,8 @@ export const computeInitialDocument = ({ fullPath }) => {
|
|
|
87
87
|
// using an interactive code widget such as number dragger.
|
|
88
88
|
// * When true, the auto-save to the file system is changed to be
|
|
89
89
|
// more frequent (throttled not debounced).
|
|
90
|
-
isInteracting: false,
|
|
90
|
+
// isInteracting: false,
|
|
91
|
+
// This is `undefined` initially.
|
|
91
92
|
};
|
|
92
93
|
|
|
93
94
|
/**
|