vzcode 0.70.0 → 0.72.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/README.md +1 -1
- package/dist/assets/{index-Bfl2hCW9.js → index-BfS1mzJK.js} +47 -47
- package/dist/assets/index-CpIQ8AoQ.css +1 -0
- package/dist/assets/{worker-D0nKlL79.js → worker-CH5jA9Si.js} +44 -44
- package/dist/index.html +2 -2
- package/package.json +20 -20
- 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/App/index.tsx +2 -0
- package/src/client/App/style.scss +6 -0
- package/src/client/App/useShareDB.ts +12 -0
- package/src/client/CodeEditor/index.tsx +6 -5
- package/src/client/CodeEditor/style.scss +4 -0
- package/src/client/Fonts/fonts.ts +8 -0
- 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 +20 -8
- package/src/client/VZMiddle.tsx +2 -0
- package/src/client/VZSettings.tsx +96 -7
- package/src/client/VZSidebar/index.tsx +8 -4
- package/src/client/VZSidebar/styles.scss +13 -11
- 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/client/useTypeScript/worker.ts +8 -1
- package/src/server/computeInitialDocument.js +2 -1
- package/src/server/index.js +1 -49
- package/src/types.ts +10 -0
- package/dist/assets/index-DOd2vdTJ.css +0 -1
|
@@ -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
|
+
};
|
|
@@ -240,6 +240,11 @@ onmessage = async ({ data }) => {
|
|
|
240
240
|
// of type '"test"' can't be used to index type '{}'."
|
|
241
241
|
const LINT_ERROR_CODE_ANY_TYPE_KEYS = 7053;
|
|
242
242
|
|
|
243
|
+
// "Property 'id' does not exist on type { ... }"
|
|
244
|
+
// Happens on objects with dynamic keys.
|
|
245
|
+
// Not valid in TypeScript, but common in JavaScript.
|
|
246
|
+
const LINT_ERROR_CODE_NON_EXISTENT_PROPERTY = 2339;
|
|
247
|
+
|
|
243
248
|
if (debug) {
|
|
244
249
|
console.log(tsErrors);
|
|
245
250
|
}
|
|
@@ -249,7 +254,9 @@ onmessage = async ({ data }) => {
|
|
|
249
254
|
error.code !== LINT_ERROR_CODE_IMPORT &&
|
|
250
255
|
error.code !== LINT_ERROR_CODE_ANY_PARAM &&
|
|
251
256
|
error.code !== LINT_ERROR_CODE_ANY_TYPE &&
|
|
252
|
-
error.code !== LINT_ERROR_CODE_ANY_TYPE_KEYS
|
|
257
|
+
error.code !== LINT_ERROR_CODE_ANY_TYPE_KEYS &&
|
|
258
|
+
error.code !==
|
|
259
|
+
LINT_ERROR_CODE_NON_EXISTENT_PROPERTY,
|
|
253
260
|
);
|
|
254
261
|
}
|
|
255
262
|
tsErrors = convertToCodeMirrorDiagnostic(tsErrors);
|
|
@@ -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
|
/**
|
package/src/server/index.js
CHANGED
|
@@ -206,60 +206,12 @@ function debounceSave() {
|
|
|
206
206
|
|
|
207
207
|
// Subscribe to listen for modifications
|
|
208
208
|
shareDBDoc.subscribe(() => {
|
|
209
|
-
shareDBDoc.on('op', (
|
|
209
|
+
shareDBDoc.on('op', () => {
|
|
210
210
|
if (shareDBDoc.data.isInteracting) {
|
|
211
211
|
throttleSave();
|
|
212
212
|
} else {
|
|
213
213
|
debounceSave();
|
|
214
214
|
}
|
|
215
|
-
|
|
216
|
-
// if (
|
|
217
|
-
// op !== null &&
|
|
218
|
-
// op[0] == 'aiStreams' &&
|
|
219
|
-
// source !== 'AIServer' &&
|
|
220
|
-
// source !== 'AIAssist'
|
|
221
|
-
// ) {
|
|
222
|
-
// //This is an insert operation (a new request)
|
|
223
|
-
// if (
|
|
224
|
-
// op[op.length - 1]['i'] !== undefined &&
|
|
225
|
-
// op[op.length - 1]['i']['AIStreamStatus'] !==
|
|
226
|
-
// undefined
|
|
227
|
-
// ) {
|
|
228
|
-
// const input =
|
|
229
|
-
// op[op.length - 1]['i']['AIStreamStatus'];
|
|
230
|
-
|
|
231
|
-
// generateAIResponse({
|
|
232
|
-
// inputText: input.text,
|
|
233
|
-
// insertionCursor: input.insertionCursor,
|
|
234
|
-
// shareDBDoc: shareDBDoc,
|
|
235
|
-
// streamId: op[op.length - 2],
|
|
236
|
-
// fileId: input.fileId,
|
|
237
|
-
// });
|
|
238
|
-
|
|
239
|
-
// const confirmStartOperation = replaceOp(
|
|
240
|
-
// [
|
|
241
|
-
// ...op.filter(
|
|
242
|
-
// (value) => typeof value === 'string',
|
|
243
|
-
// ),
|
|
244
|
-
// 'AIStreamStatus',
|
|
245
|
-
// 'serverIsRunning',
|
|
246
|
-
// ],
|
|
247
|
-
// true,
|
|
248
|
-
// true,
|
|
249
|
-
// );
|
|
250
|
-
|
|
251
|
-
// shareDBDoc.submitOp(confirmStartOperation, {
|
|
252
|
-
// source: 'AIServer',
|
|
253
|
-
// });
|
|
254
|
-
// }
|
|
255
|
-
// if (
|
|
256
|
-
// op[op.length - 1]['r'] !== null &&
|
|
257
|
-
// op[op.length - 2] == 'clientWantsToStart'
|
|
258
|
-
// ) {
|
|
259
|
-
// //client wants to halt generation
|
|
260
|
-
// haltGeneration(op[1]);
|
|
261
|
-
// }
|
|
262
|
-
// }
|
|
263
215
|
});
|
|
264
216
|
});
|
|
265
217
|
|
package/src/types.ts
CHANGED
|
@@ -76,6 +76,10 @@ export type ShareDBDoc<T> = {
|
|
|
76
76
|
event: string,
|
|
77
77
|
callback: (op: JSONOp, source: boolean) => void,
|
|
78
78
|
) => void;
|
|
79
|
+
removeListener: (
|
|
80
|
+
event: string,
|
|
81
|
+
callback: (op: JSONOp, source: boolean) => void,
|
|
82
|
+
) => void;
|
|
79
83
|
submitOp: (
|
|
80
84
|
op: JSONOp,
|
|
81
85
|
options?: any,
|
|
@@ -177,3 +181,9 @@ export type PresenceId = string;
|
|
|
177
181
|
|
|
178
182
|
// A user name for display in presence.
|
|
179
183
|
export type Username = string;
|
|
184
|
+
|
|
185
|
+
// The type of a convenience function called `submitOperation`,
|
|
186
|
+
// to submit an operation to ShareDB.
|
|
187
|
+
export type SubmitOperation = (
|
|
188
|
+
next: (content: VZCodeContent) => VZCodeContent,
|
|
189
|
+
) => void;
|