vzcode 0.17.0 → 0.19.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 +47 -39
- package/dist/assets/index-0053b846.css +1 -0
- package/dist/assets/index-34134182.js +118 -0
- package/dist/index.html +15 -5
- package/package.json +4 -4
- package/src/client/App.tsx +92 -52
- package/src/client/CodeEditor/getOrCreateEditor.ts +33 -9
- package/src/client/CodeEditor/index.tsx +15 -11
- package/src/client/CodeEditor/json1PresenceBroadcast.js +10 -3
- package/src/client/CodeEditor/json1PresenceDisplay.js +7 -2
- package/src/client/CodeEditor/widgets.ts +5 -1
- package/src/client/Resizer/index.tsx +96 -0
- package/src/client/Resizer/styles.scss +29 -0
- package/src/client/Settings.tsx +29 -21
- package/src/client/Sidebar/DirectoryArrowSVG.jsx +4 -1
- package/src/client/Sidebar/DirectoryListing.tsx +17 -5
- package/src/client/Sidebar/FileListing.tsx +4 -1
- package/src/client/Sidebar/Listing.tsx +9 -2
- package/src/client/Sidebar/index.tsx +30 -8
- package/src/client/Sidebar/styles.scss +0 -1
- package/src/client/SplitPaneResizeContext.tsx +77 -0
- package/src/client/TabList/index.tsx +7 -2
- package/src/client/diff.js +7 -1
- package/src/client/featureFlags.js +2 -1
- package/src/client/sortFileTree.ts +3 -1
- package/src/client/style.scss +18 -12
- package/src/client/themes.ts +10 -8
- package/src/client/useDynamicTheme.ts +5 -2
- package/src/client/useOpenDirectories.ts +11 -8
- package/src/client/usePrettier/index.ts +76 -57
- package/src/client/usePrettier/worker.ts +4 -1
- package/src/client/useTabsState.ts +10 -3
- package/src/randomId.js +14 -1
- package/src/server/computeInitialDocument.js +18 -5
- package/src/server/index.js +7 -2
- package/src/types.ts +11 -4
- package/dist/assets/index-ab3ae13e.js +0 -115
- package/dist/assets/index-ccd52a89.css +0 -1
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { JSONOp } from 'ot-json1';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
FileId,
|
|
4
|
+
ShareDBDoc,
|
|
5
|
+
VZCodeContent,
|
|
6
|
+
} from '../../types';
|
|
3
7
|
import { useEffect, useRef } from 'react';
|
|
4
8
|
|
|
5
9
|
// The time in milliseconds by which auto-saving is debounced.
|
|
@@ -18,7 +22,9 @@ const extension = (fileName: string) => {
|
|
|
18
22
|
|
|
19
23
|
export const usePrettier = (
|
|
20
24
|
shareDBDoc: ShareDBDoc<VZCodeContent> | null,
|
|
21
|
-
submitOperation: (
|
|
25
|
+
submitOperation: (
|
|
26
|
+
next: (content: VZCodeContent) => VZCodeContent,
|
|
27
|
+
) => void,
|
|
22
28
|
prettierWorker: Worker,
|
|
23
29
|
) => {
|
|
24
30
|
// The set of files that have been modified
|
|
@@ -38,7 +44,8 @@ export const usePrettier = (
|
|
|
38
44
|
// Get the message that comes back from the worker.
|
|
39
45
|
// This is the prettified text for a specific file.
|
|
40
46
|
const handleMessage = (event) => {
|
|
41
|
-
const { fileId, error, fileTextPrettified } =
|
|
47
|
+
const { fileId, error, fileTextPrettified } =
|
|
48
|
+
event.data;
|
|
42
49
|
if (error) {
|
|
43
50
|
console.log(error);
|
|
44
51
|
return;
|
|
@@ -59,7 +66,10 @@ export const usePrettier = (
|
|
|
59
66
|
};
|
|
60
67
|
|
|
61
68
|
// Listen for messages from the worker.
|
|
62
|
-
prettierWorker.addEventListener(
|
|
69
|
+
prettierWorker.addEventListener(
|
|
70
|
+
'message',
|
|
71
|
+
handleMessage,
|
|
72
|
+
);
|
|
63
73
|
|
|
64
74
|
const runPrettier = async () => {
|
|
65
75
|
// Get the content of the document
|
|
@@ -95,64 +105,73 @@ export const usePrettier = (
|
|
|
95
105
|
let debounceTimeout;
|
|
96
106
|
function debouncePrettier() {
|
|
97
107
|
clearTimeout(debounceTimeout);
|
|
98
|
-
debounceTimeout = setTimeout(
|
|
108
|
+
debounceTimeout = setTimeout(
|
|
109
|
+
runPrettier,
|
|
110
|
+
autoPrettierDebounceTimeMS,
|
|
111
|
+
);
|
|
99
112
|
}
|
|
100
113
|
|
|
101
114
|
// Listen for changes
|
|
102
|
-
shareDBDoc.on(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
//
|
|
109
|
-
|
|
115
|
+
shareDBDoc.on(
|
|
116
|
+
'op batch',
|
|
117
|
+
(op: JSONOp, isLocal: boolean) => {
|
|
118
|
+
// Only act on changes coming from the client
|
|
119
|
+
if (isLocal) {
|
|
120
|
+
// If the op is coming from Prettier itself,
|
|
121
|
+
// then do nothing.
|
|
122
|
+
if (isApplyingOpRef.current) {
|
|
123
|
+
// console.log('ignoring op from Prettier');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Example op that we want to act on:
|
|
128
|
+
// op [
|
|
129
|
+
// "files",
|
|
130
|
+
// "2514857669",
|
|
131
|
+
// "text",
|
|
132
|
+
// {
|
|
133
|
+
// "es": [
|
|
134
|
+
// 18,
|
|
135
|
+
// "d"
|
|
136
|
+
// ]
|
|
137
|
+
// }
|
|
138
|
+
// ]
|
|
139
|
+
|
|
140
|
+
// Check if the path of this op is the text content of a file
|
|
141
|
+
if (
|
|
142
|
+
op &&
|
|
143
|
+
op.length === 4 &&
|
|
144
|
+
op[0] === 'files' &&
|
|
145
|
+
typeof op[1] === 'string' &&
|
|
146
|
+
op[2] === 'text'
|
|
147
|
+
) {
|
|
148
|
+
// Get the file id
|
|
149
|
+
const fileId: FileId = op[1];
|
|
150
|
+
|
|
151
|
+
// Add the file id to the set of dirty files
|
|
152
|
+
dirtyFiles.add(fileId);
|
|
153
|
+
|
|
154
|
+
// Debounce running Prettier
|
|
155
|
+
debouncePrettier();
|
|
156
|
+
|
|
157
|
+
// console.log('Op is for file', fileId);
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
// console.log('ignoring op from remote', op, isLocal);
|
|
110
161
|
}
|
|
111
162
|
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// 18,
|
|
120
|
-
// "d"
|
|
121
|
-
// ]
|
|
122
|
-
// }
|
|
123
|
-
// ]
|
|
124
|
-
|
|
125
|
-
// Check if the path of this op is the text content of a file
|
|
126
|
-
if (
|
|
127
|
-
op &&
|
|
128
|
-
op.length === 4 &&
|
|
129
|
-
op[0] === 'files' &&
|
|
130
|
-
typeof op[1] === 'string' &&
|
|
131
|
-
op[2] === 'text'
|
|
132
|
-
) {
|
|
133
|
-
// Get the file id
|
|
134
|
-
const fileId: FileId = op[1];
|
|
135
|
-
|
|
136
|
-
// Add the file id to the set of dirty files
|
|
137
|
-
dirtyFiles.add(fileId);
|
|
138
|
-
|
|
139
|
-
// Debounce running Prettier
|
|
140
|
-
debouncePrettier();
|
|
141
|
-
|
|
142
|
-
// console.log('Op is for file', fileId);
|
|
143
|
-
}
|
|
144
|
-
} else {
|
|
145
|
-
// console.log('ignoring op from remote', op, isLocal);
|
|
146
|
-
}
|
|
163
|
+
// In the event that the component unmounts,
|
|
164
|
+
return () => {
|
|
165
|
+
// Remove the event listener
|
|
166
|
+
prettierWorker.removeEventListener(
|
|
167
|
+
'message',
|
|
168
|
+
handleMessage,
|
|
169
|
+
);
|
|
147
170
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// Clear the timeout
|
|
154
|
-
clearTimeout(debounceTimeout);
|
|
155
|
-
};
|
|
156
|
-
});
|
|
171
|
+
// Clear the timeout
|
|
172
|
+
clearTimeout(debounceTimeout);
|
|
173
|
+
};
|
|
174
|
+
},
|
|
175
|
+
);
|
|
157
176
|
}, [shareDBDoc]);
|
|
158
177
|
};
|
|
@@ -11,20 +11,27 @@ export const useTabsState = (
|
|
|
11
11
|
// Called when a tab is closed.
|
|
12
12
|
const closeTab = useCallback(
|
|
13
13
|
(fileIdToRemove: FileId) => {
|
|
14
|
-
const i = tabList.findIndex(
|
|
14
|
+
const i = tabList.findIndex(
|
|
15
|
+
(fileId) => fileId === fileIdToRemove,
|
|
16
|
+
);
|
|
15
17
|
|
|
16
18
|
// Support calling `closeTab` on a fileId that is not open,
|
|
17
19
|
// such as when a file is deleted..
|
|
18
20
|
if (i !== -1) {
|
|
19
21
|
// Remove the tab from the tab list.
|
|
20
|
-
const newTabList = [
|
|
22
|
+
const newTabList = [
|
|
23
|
+
...tabList.slice(0, i),
|
|
24
|
+
...tabList.slice(i + 1),
|
|
25
|
+
];
|
|
21
26
|
setTabList(newTabList);
|
|
22
27
|
|
|
23
28
|
// If we are closing the active file,
|
|
24
29
|
if (activeFileId === fileIdToRemove) {
|
|
25
30
|
// set the new active file to the next tab over,
|
|
26
31
|
if (newTabList.length > 0) {
|
|
27
|
-
setActiveFileId(
|
|
32
|
+
setActiveFileId(
|
|
33
|
+
i === 0 ? newTabList[i] : newTabList[i - 1],
|
|
34
|
+
);
|
|
28
35
|
} else {
|
|
29
36
|
// or clear out the active file
|
|
30
37
|
// if we've closed the last tab.
|
package/src/randomId.js
CHANGED
|
@@ -1,2 +1,15 @@
|
|
|
1
1
|
// Generate a random ID string consisting of digits.
|
|
2
|
-
|
|
2
|
+
const numDigits = 8;
|
|
3
|
+
export const randomId = () => {
|
|
4
|
+
let randomString = '';
|
|
5
|
+
for (let i = 0; i < numDigits; i++) {
|
|
6
|
+
randomString += Math.floor(Math.random() * 10);
|
|
7
|
+
}
|
|
8
|
+
return randomString;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// const probabilityOfCollision =
|
|
12
|
+
// 1 - Math.pow(1 - 1 / Math.pow(10, numDigits), numRuns);
|
|
13
|
+
// Using this formula, the probability of generating the same ID twice
|
|
14
|
+
// when using 8 digits and running the code 1000 times is approximately
|
|
15
|
+
// 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { randomId } from '../randomId.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
enableDirectories,
|
|
6
|
+
debugDirectories,
|
|
7
|
+
} from './featureFlags.js';
|
|
5
8
|
|
|
6
9
|
const isDirectory = (file) => file.endsWith('/');
|
|
7
10
|
|
|
@@ -36,10 +39,17 @@ export const computeInitialDocument = ({ fullPath }) => {
|
|
|
36
39
|
|
|
37
40
|
while (unsearchedDirectories.length !== 0) {
|
|
38
41
|
const currentDirectory = unsearchedDirectories.pop();
|
|
39
|
-
const currentDirectoryPath = path.join(
|
|
42
|
+
const currentDirectoryPath = path.join(
|
|
43
|
+
fullPath,
|
|
44
|
+
currentDirectory,
|
|
45
|
+
);
|
|
40
46
|
const newFiles = fs
|
|
41
|
-
.readdirSync(currentDirectoryPath, {
|
|
42
|
-
|
|
47
|
+
.readdirSync(currentDirectoryPath, {
|
|
48
|
+
withFileTypes: true,
|
|
49
|
+
})
|
|
50
|
+
.filter((dirent) =>
|
|
51
|
+
enableDirectories ? true : dirent.isFile(),
|
|
52
|
+
)
|
|
43
53
|
|
|
44
54
|
// Add a trailing slash for directories
|
|
45
55
|
.map((dirent) => {
|
|
@@ -64,7 +74,10 @@ export const computeInitialDocument = ({ fullPath }) => {
|
|
|
64
74
|
initialDocument.files[id] = {
|
|
65
75
|
text: isDirectory(file)
|
|
66
76
|
? null
|
|
67
|
-
: fs.readFileSync(
|
|
77
|
+
: fs.readFileSync(
|
|
78
|
+
path.join(fullPath, file),
|
|
79
|
+
'utf-8',
|
|
80
|
+
),
|
|
68
81
|
name: file,
|
|
69
82
|
};
|
|
70
83
|
});
|
package/src/server/index.js
CHANGED
|
@@ -163,7 +163,10 @@ function throttleSave() {
|
|
|
163
163
|
let debounceTimeout;
|
|
164
164
|
function debounceSave() {
|
|
165
165
|
clearTimeout(debounceTimeout);
|
|
166
|
-
debounceTimeout = setTimeout(
|
|
166
|
+
debounceTimeout = setTimeout(
|
|
167
|
+
save,
|
|
168
|
+
autoSaveDebounceTimeMS,
|
|
169
|
+
);
|
|
167
170
|
}
|
|
168
171
|
|
|
169
172
|
// Subscribe to listen for modifications
|
|
@@ -186,7 +189,9 @@ server.listen(port, async () => {
|
|
|
186
189
|
open(url);
|
|
187
190
|
})();
|
|
188
191
|
} else {
|
|
189
|
-
console.log(
|
|
192
|
+
console.log(
|
|
193
|
+
`Editor is live at http://localhost:${port}`,
|
|
194
|
+
);
|
|
190
195
|
open(`http://localhost:${port}`);
|
|
191
196
|
}
|
|
192
197
|
});
|
package/src/types.ts
CHANGED
|
@@ -67,9 +67,16 @@ export type ShareDBDoc<T> = {
|
|
|
67
67
|
data: T;
|
|
68
68
|
ingestSnapshot: (snapshot: any, callback) => void;
|
|
69
69
|
subscribe: (callback) => void;
|
|
70
|
-
on: (
|
|
70
|
+
on: (
|
|
71
|
+
event: string,
|
|
72
|
+
callback: (op: JSONOp, source: boolean) => void,
|
|
73
|
+
) => void;
|
|
71
74
|
off: (event: string, callback: () => void) => void;
|
|
72
|
-
submitOp: (
|
|
75
|
+
submitOp: (
|
|
76
|
+
op: JSONOp,
|
|
77
|
+
options?: any,
|
|
78
|
+
callback?: () => void,
|
|
79
|
+
) => void;
|
|
73
80
|
};
|
|
74
81
|
|
|
75
82
|
// The ShareDB document type for VZCode.
|
|
@@ -82,7 +89,7 @@ export type VZCodeContent = {
|
|
|
82
89
|
// * `true` when the user is interacting
|
|
83
90
|
// via interactive code widgets (e.g. Alt+drag)
|
|
84
91
|
// * Hot reloading is throttled when this is `true`.
|
|
85
|
-
// * `false` when they are not (e.g. normal typing)
|
|
92
|
+
// * `false` or `undefined` when they are not (e.g. normal typing)
|
|
86
93
|
// * Hot reloading is debounced when this is `false`.
|
|
87
|
-
isInteracting
|
|
94
|
+
isInteracting?: boolean;
|
|
88
95
|
};
|