vzcode 1.30.1 → 1.32.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-zzK6rRiK.css → index-DTtcN2MP.css} +1 -1
- package/dist/assets/index-sreAszZh.js +240 -0
- package/dist/assets/worker-BKfYWklR.js +136 -0
- package/dist/assets/{index-Dd8gk_1S.js → worker-COyDRdqW.js} +109 -103
- package/dist/assets/{worker-CaP6zYz7.js → worker-CWsWXMyk.js} +70 -70
- package/dist/index.html +2 -2
- package/package.json +42 -36
- package/src/client/AIAssist/startAIAssist.ts +0 -24
- package/src/client/App/index.tsx +14 -7
- package/src/client/CodeEditor/getOrCreateEditor.ts +80 -56
- package/src/client/CodeEditor/index.tsx +56 -30
- package/src/client/CodeEditor/typescriptExtension/worker.ts +32 -0
- package/src/client/RunCodeWidget/index.tsx +0 -2
- package/src/client/VZCodeContext.tsx +8 -25
- package/src/client/VZMiddle.tsx +11 -5
- package/src/client/VZSidebar/Search.tsx +11 -0
- package/src/client/VZSidebar/index.tsx +18 -11
- package/src/client/VZSidebar/styles.scss +27 -7
- package/src/client/VZSidebar/useDragAndDrop.tsx +237 -35
- package/src/client/main.jsx +0 -2
- package/src/client/useESLint/index.ts +72 -0
- package/src/client/useESLint/worker.ts +113 -0
- package/src/client/useFileCRUD.ts +0 -2
- package/src/server/featureFlags.js +4 -6
- package/src/server/setupEnv.js +0 -10
- package/dist/assets/index-BOiH3_fC.js +0 -234
- package/src/client/CodeEditor/typeScriptCompletions.ts +0 -134
- package/src/client/CodeEditor/typeScriptLinter.ts +0 -47
- package/src/client/useTypeScript/index.ts +0 -48
- package/src/client/useTypeScript/worker/constants.ts +0 -94
- package/src/client/useTypeScript/worker/getTSFileName.ts +0 -4
- package/src/client/useTypeScript/worker/handleMessageAutocompleteRequest.ts +0 -63
- package/src/client/useTypeScript/worker/handleMessageLintRequest.ts +0 -84
- package/src/client/useTypeScript/worker/handleMessageTranspileRequest.ts +0 -20
- package/src/client/useTypeScript/worker/handleMessageUpdateContent.ts +0 -42
- package/src/client/useTypeScript/worker/index.ts +0 -110
- package/src/client/useTypeScript/worker/isTS.ts +0 -3
- package/src/client/useTypeScript/worker/requestTypes.ts +0 -31
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-sreAszZh.js"></script>
|
|
24
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DTtcN2MP.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": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"description": "Multiplayer code editor system",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"test": "vitest run",
|
|
14
14
|
"test-interactive": "cd test/sampleDirectories/kitchenSink && node ../../../src/server/index.js",
|
|
15
15
|
"prettier": "prettier {*.*,**/*.*} --write",
|
|
16
|
-
"
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
17
|
"dev": "cross-env EDITOR_PORT=5173 concurrently \"npm run test-interactive\" \"vite\"",
|
|
18
18
|
"build": "vite build",
|
|
19
19
|
"build-release": "vite build --mode release",
|
|
@@ -107,73 +107,79 @@
|
|
|
107
107
|
"@codemirror/autocomplete": "^6.18.6",
|
|
108
108
|
"@codemirror/lang-css": "^6.3.1",
|
|
109
109
|
"@codemirror/lang-html": "^6.4.9",
|
|
110
|
-
"@codemirror/lang-javascript": "^6.2.
|
|
110
|
+
"@codemirror/lang-javascript": "^6.2.4",
|
|
111
111
|
"@codemirror/lang-json": "^6.0.1",
|
|
112
112
|
"@codemirror/lang-markdown": "^6.3.2",
|
|
113
|
+
"@codemirror/lint": "^6.8.5",
|
|
113
114
|
"@codemirror/state": "^6.5.2",
|
|
114
115
|
"@codemirror/theme-one-dark": "^6.1.2",
|
|
115
|
-
"@codemirror/view": "^6.
|
|
116
|
-
"@langchain/core": "^0.3.
|
|
117
|
-
"@langchain/openai": "^0.5.
|
|
116
|
+
"@codemirror/view": "^6.37.1",
|
|
117
|
+
"@langchain/core": "^0.3.57",
|
|
118
|
+
"@langchain/openai": "^0.5.12",
|
|
118
119
|
"@lezer/highlight": "^1.2.1",
|
|
119
|
-
"@livekit/components-react": "^2.9.
|
|
120
|
+
"@livekit/components-react": "^2.9.9",
|
|
120
121
|
"@replit/codemirror-indentation-markers": "^6.5.3",
|
|
121
122
|
"@replit/codemirror-interact": "^6.3.1",
|
|
122
123
|
"@replit/codemirror-lang-svelte": "^6.0.0",
|
|
123
124
|
"@replit/codemirror-vscode-keymap": "^6.0.2",
|
|
124
125
|
"@teamwork/websocket-json-stream": "^2.0.0",
|
|
125
126
|
"@typescript/vfs": "^1.6.1",
|
|
126
|
-
"@uiw/codemirror-theme-abcdef": "^4.23.
|
|
127
|
-
"@uiw/codemirror-theme-dracula": "^4.23.
|
|
128
|
-
"@uiw/codemirror-theme-eclipse": "^4.23.
|
|
129
|
-
"@uiw/codemirror-theme-github": "^4.23.
|
|
130
|
-
"@uiw/codemirror-theme-material": "^4.23.
|
|
131
|
-
"@uiw/codemirror-theme-nord": "^4.23.
|
|
132
|
-
"@uiw/codemirror-theme-okaidia": "^4.23.
|
|
133
|
-
"@uiw/codemirror-theme-xcode": "^4.23.
|
|
134
|
-
"@uiw/codemirror-themes": "^4.23.
|
|
135
|
-
"@
|
|
127
|
+
"@uiw/codemirror-theme-abcdef": "^4.23.12",
|
|
128
|
+
"@uiw/codemirror-theme-dracula": "^4.23.12",
|
|
129
|
+
"@uiw/codemirror-theme-eclipse": "^4.23.12",
|
|
130
|
+
"@uiw/codemirror-theme-github": "^4.23.12",
|
|
131
|
+
"@uiw/codemirror-theme-material": "^4.23.12",
|
|
132
|
+
"@uiw/codemirror-theme-nord": "^4.23.12",
|
|
133
|
+
"@uiw/codemirror-theme-okaidia": "^4.23.12",
|
|
134
|
+
"@uiw/codemirror-theme-xcode": "^4.23.12",
|
|
135
|
+
"@uiw/codemirror-themes": "^4.23.12",
|
|
136
|
+
"@valtown/codemirror-ts": "^2.3.1",
|
|
137
|
+
"@vizhub/viz-types": "^0.1.0",
|
|
136
138
|
"body-parser": "^2.2.0",
|
|
137
139
|
"codemirror": "^6.0.1",
|
|
138
140
|
"codemirror-copilot": "^0.0.7",
|
|
139
141
|
"codemirror-ot": "^4.4.0",
|
|
140
142
|
"color-hash": "^2.0.2",
|
|
143
|
+
"comlink": "^4.4.2",
|
|
141
144
|
"d3-array": "^3.2.4",
|
|
142
145
|
"diff-match-patch": "^1.0.5",
|
|
143
|
-
"dotenv": "^16.
|
|
146
|
+
"dotenv": "^16.5.0",
|
|
147
|
+
"eslint": "^9.28.0",
|
|
148
|
+
"eslint-linter-browserify": "^9.28.0",
|
|
144
149
|
"express": "^5.1.0",
|
|
145
|
-
"
|
|
150
|
+
"globals": "^16.2.0",
|
|
151
|
+
"ignore": "^7.0.5",
|
|
146
152
|
"json0-ot-diff": "^1.1.2",
|
|
147
|
-
"livekit-server-sdk": "^2.
|
|
153
|
+
"livekit-server-sdk": "^2.13.0",
|
|
148
154
|
"ngrok": "^5.0.0-beta.2",
|
|
149
|
-
"npm": "^11.
|
|
150
|
-
"open": "^10.1.
|
|
151
|
-
"prettier-plugin-svelte": "^3.
|
|
155
|
+
"npm": "^11.4.1",
|
|
156
|
+
"open": "^10.1.2",
|
|
157
|
+
"prettier-plugin-svelte": "^3.4.0",
|
|
152
158
|
"react": "^18",
|
|
153
|
-
"react-bootstrap": "^2.10.
|
|
159
|
+
"react-bootstrap": "^2.10.10",
|
|
154
160
|
"react-dom": "^18",
|
|
155
|
-
"react-router-dom": "^7.
|
|
156
|
-
"sharedb": "^5.2.
|
|
157
|
-
"sharedb-client-browser": "^5.
|
|
161
|
+
"react-router-dom": "^7.6.2",
|
|
162
|
+
"sharedb": "^5.2.2",
|
|
163
|
+
"sharedb-client-browser": "^5.2.2",
|
|
158
164
|
"uuid": "^11.1.0",
|
|
159
165
|
"vizhub-ui": "^3.23.0",
|
|
160
|
-
"ws": "^8.18.
|
|
166
|
+
"ws": "^8.18.2"
|
|
161
167
|
},
|
|
162
168
|
"devDependencies": {
|
|
163
169
|
"@types/react": "^18",
|
|
164
170
|
"@types/react-dom": "^18",
|
|
165
|
-
"@vitejs/plugin-react": "^4.
|
|
171
|
+
"@vitejs/plugin-react": "^4.5.1",
|
|
166
172
|
"concurrently": "^9.1.2",
|
|
167
173
|
"cross-env": "^7.0.3",
|
|
168
|
-
"npm-check-updates": "^
|
|
174
|
+
"npm-check-updates": "^18.0.1",
|
|
169
175
|
"prettier": "^3.5.3",
|
|
170
|
-
"sass": "^1.
|
|
171
|
-
"typescript": "^5.8.
|
|
172
|
-
"vite": "^6.
|
|
173
|
-
"vitest": "^3.
|
|
176
|
+
"sass": "^1.89.1",
|
|
177
|
+
"typescript": "^5.8.3",
|
|
178
|
+
"vite": "^6.3.5",
|
|
179
|
+
"vitest": "^3.2.2"
|
|
174
180
|
},
|
|
175
181
|
"optionalDependencies": {
|
|
176
|
-
"@rollup/rollup-darwin-arm64": "^4.
|
|
177
|
-
"@rollup/rollup-win32-x64-msvc": "^4.
|
|
182
|
+
"@rollup/rollup-darwin-arm64": "^4.42.0",
|
|
183
|
+
"@rollup/rollup-win32-x64-msvc": "^4.42.0"
|
|
178
184
|
}
|
|
179
185
|
}
|
|
@@ -70,30 +70,6 @@ export const startAIAssist = async ({
|
|
|
70
70
|
.join('\n\n');
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
if (debug) {
|
|
74
|
-
// console.log('[startAIAssist] sending HTTP request:');
|
|
75
|
-
// console.log(
|
|
76
|
-
// '[startAIAssist] aiAssistEndpoint:',
|
|
77
|
-
// aiAssistEndpoint,
|
|
78
|
-
// );
|
|
79
|
-
// console.log(
|
|
80
|
-
// '[startAIAssist] aiAssistOptions:',
|
|
81
|
-
// aiAssistOptions,
|
|
82
|
-
// );
|
|
83
|
-
console.log(
|
|
84
|
-
'[startAIAssist] inputText:\n`' + inputText + '`',
|
|
85
|
-
);
|
|
86
|
-
// console.log('[startAIAssist] fileId:', fileId);
|
|
87
|
-
// console.log(
|
|
88
|
-
// '[startAIAssist] insertionCursor:',
|
|
89
|
-
// insertionCursor,
|
|
90
|
-
// );
|
|
91
|
-
// console.log(
|
|
92
|
-
// '[startAIAssist] aiStreamId:',
|
|
93
|
-
// aiStreamId,
|
|
94
|
-
// );
|
|
95
|
-
}
|
|
96
|
-
|
|
97
73
|
const response = await fetch(aiAssistEndpoint, {
|
|
98
74
|
method: 'POST',
|
|
99
75
|
headers: {
|
package/src/client/App/index.tsx
CHANGED
|
@@ -19,20 +19,17 @@ import { VZLeft } from '../VZLeft';
|
|
|
19
19
|
import { VZMiddle } from '../VZMiddle';
|
|
20
20
|
import { VZResizer } from '../VZResizer';
|
|
21
21
|
import { VZRight } from '../VZRight';
|
|
22
|
-
import TypeScriptWorker from '../useTypeScript/worker?worker';
|
|
23
22
|
import {
|
|
24
23
|
useInitialUsername,
|
|
25
24
|
usePersistUsername,
|
|
26
25
|
} from '../usernameLocalStorage';
|
|
27
26
|
import './style.scss';
|
|
28
27
|
import { useShareDB } from './useShareDB';
|
|
28
|
+
import { useESLint } from '../useESLint';
|
|
29
29
|
|
|
30
30
|
// Instantiate the Prettier worker.
|
|
31
31
|
const prettierWorker = new PrettierWorker();
|
|
32
32
|
|
|
33
|
-
// Instantiate the TypeScript worker.
|
|
34
|
-
const typeScriptWorker = new TypeScriptWorker();
|
|
35
|
-
|
|
36
33
|
// Register our custom JSON1 OT type that supports presence.
|
|
37
34
|
// See https://github.com/vizhub-core/json1-presence
|
|
38
35
|
ShareDBClient.types.register(json1Presence.type);
|
|
@@ -79,6 +76,7 @@ function App() {
|
|
|
79
76
|
useState(v4()); //default room name will be an arbitrary uuid
|
|
80
77
|
const [liveKitConnection, setLiveKitConnection] =
|
|
81
78
|
useState(false);
|
|
79
|
+
const { esLintSource } = useESLint();
|
|
82
80
|
// Get the initial username from localStorage.
|
|
83
81
|
const initialUsername: Username = useInitialUsername();
|
|
84
82
|
|
|
@@ -93,6 +91,14 @@ function App() {
|
|
|
93
91
|
// so that multiple browser windows are not required.
|
|
94
92
|
const enableRightPanel = true;
|
|
95
93
|
|
|
94
|
+
// TODO: enable this when the AI copilot is ready
|
|
95
|
+
// Currently it's glitchy and frustrating to use.
|
|
96
|
+
// It appears to be bugs in the upstream CodeMirror copilot code.
|
|
97
|
+
// Ghost text appears after just moving the cursor, not typing.
|
|
98
|
+
// It's hard to figure out how to dismiss it.
|
|
99
|
+
// Clicking on it accepts it but should not.
|
|
100
|
+
const enableCopilot = false;
|
|
101
|
+
|
|
96
102
|
return (
|
|
97
103
|
<SplitPaneResizeProvider>
|
|
98
104
|
<VZCodeProvider
|
|
@@ -102,7 +108,6 @@ function App() {
|
|
|
102
108
|
localPresence={localPresence}
|
|
103
109
|
docPresence={docPresence}
|
|
104
110
|
prettierWorker={prettierWorker}
|
|
105
|
-
typeScriptWorker={typeScriptWorker}
|
|
106
111
|
initialUsername={initialUsername}
|
|
107
112
|
connected={connected}
|
|
108
113
|
pending={pending}
|
|
@@ -123,8 +128,10 @@ function App() {
|
|
|
123
128
|
<div className="app">
|
|
124
129
|
<VZLeft />
|
|
125
130
|
<VZMiddle
|
|
126
|
-
|
|
127
|
-
|
|
131
|
+
aiCopilotEndpoint={
|
|
132
|
+
enableCopilot ? '/ai-copilot' : null
|
|
133
|
+
}
|
|
134
|
+
esLintSource={esLintSource}
|
|
128
135
|
/>
|
|
129
136
|
{enableRightPanel ? <VZRight /> : null}
|
|
130
137
|
<VZResizer side="left" />
|
|
@@ -2,6 +2,7 @@ import { EditorView } from 'codemirror';
|
|
|
2
2
|
import {
|
|
3
3
|
Compartment,
|
|
4
4
|
EditorState,
|
|
5
|
+
StateField,
|
|
5
6
|
} from '@codemirror/state';
|
|
6
7
|
import { javascript } from '@codemirror/lang-javascript';
|
|
7
8
|
import { svelte } from '@replit/codemirror-lang-svelte';
|
|
@@ -15,7 +16,11 @@ import { autocompletion } from '@codemirror/autocomplete';
|
|
|
15
16
|
import { indentationMarkers } from '@replit/codemirror-indentation-markers';
|
|
16
17
|
// import { showMinimap } from '@replit/codemirror-minimap';
|
|
17
18
|
import { vscodeKeymap } from '@replit/codemirror-vscode-keymap';
|
|
18
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
Diagnostic,
|
|
21
|
+
linter,
|
|
22
|
+
lintGutter,
|
|
23
|
+
} from '@codemirror/lint';
|
|
19
24
|
|
|
20
25
|
import { json1Presence, textUnicode } from '../../ot';
|
|
21
26
|
import {
|
|
@@ -38,30 +43,57 @@ import {
|
|
|
38
43
|
EditorCacheValue,
|
|
39
44
|
} from '../useEditorCache';
|
|
40
45
|
import { ThemeLabel, themeOptionsByLabel } from '../themes';
|
|
41
|
-
import { typeScriptCompletions } from './typeScriptCompletions';
|
|
42
|
-
import { typeScriptLinter } from './typeScriptLinter';
|
|
43
46
|
import { keymap } from '@codemirror/view';
|
|
44
47
|
import { basicSetup } from './basicSetup';
|
|
45
48
|
import { InteractRule } from '@replit/codemirror-interact';
|
|
46
|
-
import rainbowBrackets from '
|
|
49
|
+
import rainbowBrackets from './rainbowBrackets';
|
|
47
50
|
import { cssLanguage } from '@codemirror/lang-css';
|
|
48
51
|
import { javascriptLanguage } from '@codemirror/lang-javascript';
|
|
49
52
|
import { copilot } from './Copilot';
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
import { type WorkerShape } from '@valtown/codemirror-ts/src/worker';
|
|
54
|
+
import * as Comlink from 'comlink';
|
|
55
|
+
import {
|
|
56
|
+
tsAutocompleteWorker,
|
|
57
|
+
tsFacetWorker,
|
|
58
|
+
tsHoverWorker,
|
|
59
|
+
tsLinterWorker,
|
|
60
|
+
tsSyncWorker,
|
|
61
|
+
} from '@valtown/codemirror-ts';
|
|
58
62
|
|
|
59
63
|
const DEBUG = false;
|
|
60
64
|
|
|
65
|
+
// Define a StateField to store the file name.
|
|
66
|
+
// This should be defined at the module level if it's to be imported by other modules.
|
|
67
|
+
export const fileNameStateField = StateField.define<string>(
|
|
68
|
+
{
|
|
69
|
+
create: () => '', // Default initial value
|
|
70
|
+
update: (value, tr) => value, // Typically set once at creation for a given editor instance
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
61
74
|
// Enables TypeScript +JSX support in CodeMirror.
|
|
62
75
|
const tsx = () =>
|
|
63
76
|
javascript({ jsx: true, typescript: true });
|
|
64
77
|
|
|
78
|
+
// Lazy initialization of worker
|
|
79
|
+
let worker: Comlink.Remote<WorkerShape> | null = null;
|
|
80
|
+
const initializeWorker = async () => {
|
|
81
|
+
if (worker === null) {
|
|
82
|
+
const innerWorker = new Worker(
|
|
83
|
+
new URL(
|
|
84
|
+
'./typescriptExtension/worker.ts',
|
|
85
|
+
import.meta.url,
|
|
86
|
+
),
|
|
87
|
+
{
|
|
88
|
+
type: 'module',
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
worker = Comlink.wrap<WorkerShape>(innerWorker);
|
|
92
|
+
await worker.initialize();
|
|
93
|
+
}
|
|
94
|
+
return worker;
|
|
95
|
+
};
|
|
96
|
+
|
|
65
97
|
const htmlConfig = {
|
|
66
98
|
matchClosingTags: true,
|
|
67
99
|
selfClosingTags: false,
|
|
@@ -120,7 +152,7 @@ interface ExtendedEditorCacheValue
|
|
|
120
152
|
|
|
121
153
|
// Gets or creates an `editorCache` entry for the given file id.
|
|
122
154
|
// Looks in `editorCache` first, and if not found, creates a new editor.
|
|
123
|
-
export const getOrCreateEditor = ({
|
|
155
|
+
export const getOrCreateEditor = async ({
|
|
124
156
|
paneId = 'root',
|
|
125
157
|
fileId,
|
|
126
158
|
shareDBDoc,
|
|
@@ -132,12 +164,11 @@ export const getOrCreateEditor = ({
|
|
|
132
164
|
onInteract,
|
|
133
165
|
editorCache,
|
|
134
166
|
usernameRef,
|
|
135
|
-
typeScriptWorker,
|
|
136
167
|
customInteractRules,
|
|
137
|
-
allowGlobals,
|
|
138
168
|
enableAutoFollowRef,
|
|
139
169
|
openTab,
|
|
140
170
|
aiCopilotEndpoint,
|
|
171
|
+
esLintSource,
|
|
141
172
|
rainbowBracketsEnabled = true,
|
|
142
173
|
}: {
|
|
143
174
|
// TODO pass this in from the outside
|
|
@@ -167,17 +198,18 @@ export const getOrCreateEditor = ({
|
|
|
167
198
|
editorCache: EditorCache;
|
|
168
199
|
usernameRef: React.MutableRefObject<Username>;
|
|
169
200
|
aiAssistEndpoint?: string;
|
|
170
|
-
typeScriptWorker: Worker;
|
|
171
201
|
customInteractRules?: Array<InteractRule>;
|
|
172
|
-
allowGlobals: boolean;
|
|
173
202
|
|
|
174
203
|
// Ref to a boolean that determines whether to
|
|
175
204
|
// enable auto-following the cursors of remote users.
|
|
176
205
|
enableAutoFollowRef: React.MutableRefObject<boolean>;
|
|
177
206
|
openTab: (tabState: TabState) => void;
|
|
178
207
|
aiCopilotEndpoint?: string;
|
|
208
|
+
esLintSource: (
|
|
209
|
+
view: EditorView,
|
|
210
|
+
) => Promise<readonly Diagnostic[]>;
|
|
179
211
|
rainbowBracketsEnabled?: boolean; // New parameter type
|
|
180
|
-
}): ExtendedEditorCacheValue => {
|
|
212
|
+
}): Promise<ExtendedEditorCacheValue> => {
|
|
181
213
|
// Cache hit
|
|
182
214
|
|
|
183
215
|
const cacheKey = editorCacheKey(fileId, paneId);
|
|
@@ -208,6 +240,9 @@ export const getOrCreateEditor = ({
|
|
|
208
240
|
// const extensions = [autocompletion(), html(htmlConfig)]
|
|
209
241
|
const extensions = [];
|
|
210
242
|
|
|
243
|
+
// Initialize the fileNameStateField with the actual file name
|
|
244
|
+
extensions.push(fileNameStateField.init(() => name));
|
|
245
|
+
|
|
211
246
|
// This plugin implements multiplayer editing,
|
|
212
247
|
// real-time synchronozation of changes across clients.
|
|
213
248
|
// Does not deal with showing others' cursors.
|
|
@@ -258,6 +293,16 @@ export const getOrCreateEditor = ({
|
|
|
258
293
|
// https://github.com/vizhub-core/vzcode/issues/134
|
|
259
294
|
extensions.push(basicSetup);
|
|
260
295
|
|
|
296
|
+
if (esLintSource) {
|
|
297
|
+
extensions.push(lintGutter()); // Show lint icons in the gutter
|
|
298
|
+
extensions.push(
|
|
299
|
+
linter(esLintSource, {
|
|
300
|
+
// You can configure linter options here, e.g., delay
|
|
301
|
+
delay: 750,
|
|
302
|
+
}),
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
261
306
|
// This supports dynamic changing of the theme.
|
|
262
307
|
extensions.push(
|
|
263
308
|
themeCompartment.of(themeOptionsByLabel[theme].value),
|
|
@@ -333,44 +378,6 @@ export const getOrCreateEditor = ({
|
|
|
333
378
|
// }),
|
|
334
379
|
// );
|
|
335
380
|
|
|
336
|
-
// Add the extension that provides TypeScript completions.
|
|
337
|
-
// only add this if it's TS-compatible (.js, .jsx, .ts, .tsx)
|
|
338
|
-
const isTypeScript =
|
|
339
|
-
fileExtension === 'js' ||
|
|
340
|
-
fileExtension === 'jsx' ||
|
|
341
|
-
fileExtension === 'ts' ||
|
|
342
|
-
fileExtension === 'tsx';
|
|
343
|
-
|
|
344
|
-
extensions.push(
|
|
345
|
-
autocompletion(
|
|
346
|
-
isTypeScript
|
|
347
|
-
? {
|
|
348
|
-
override: [
|
|
349
|
-
typeScriptCompletions({
|
|
350
|
-
typeScriptWorker,
|
|
351
|
-
fileName: name,
|
|
352
|
-
}),
|
|
353
|
-
],
|
|
354
|
-
}
|
|
355
|
-
: undefined,
|
|
356
|
-
),
|
|
357
|
-
);
|
|
358
|
-
|
|
359
|
-
if (shareDBDoc && enableTypeScriptLinter) {
|
|
360
|
-
extensions.push(
|
|
361
|
-
linter(
|
|
362
|
-
typeScriptLinter({
|
|
363
|
-
typeScriptWorker,
|
|
364
|
-
fileName: name,
|
|
365
|
-
shareDBDoc,
|
|
366
|
-
fileId,
|
|
367
|
-
allowGlobals,
|
|
368
|
-
}) as unknown as () => Diagnostic[],
|
|
369
|
-
//Needs the unknown because we are returning a Promise<Diagnostic>
|
|
370
|
-
),
|
|
371
|
-
);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
381
|
// Add the extension that provides indentation markers.
|
|
375
382
|
extensions.push(
|
|
376
383
|
indentationMarkers({
|
|
@@ -384,6 +391,23 @@ export const getOrCreateEditor = ({
|
|
|
384
391
|
}),
|
|
385
392
|
);
|
|
386
393
|
|
|
394
|
+
if (name.endsWith('ts') || name.endsWith('tsx')) {
|
|
395
|
+
// Initialize worker if needed
|
|
396
|
+
const tsWorker = await initializeWorker();
|
|
397
|
+
|
|
398
|
+
extensions.push(
|
|
399
|
+
...[
|
|
400
|
+
tsFacetWorker.of({ worker: tsWorker, path: name }),
|
|
401
|
+
tsSyncWorker(),
|
|
402
|
+
tsLinterWorker(),
|
|
403
|
+
autocompletion({
|
|
404
|
+
override: [tsAutocompleteWorker()],
|
|
405
|
+
}),
|
|
406
|
+
tsHoverWorker(),
|
|
407
|
+
],
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
387
411
|
// Show the minimap
|
|
388
412
|
// See https://github.com/replit/codemirror-minimap#usage
|
|
389
413
|
// This extension has poor performance, so it's disabled for now.
|
|
@@ -2,15 +2,17 @@ import {
|
|
|
2
2
|
useRef,
|
|
3
3
|
useLayoutEffect,
|
|
4
4
|
useCallback,
|
|
5
|
-
useMemo,
|
|
6
5
|
useContext,
|
|
7
6
|
useEffect,
|
|
7
|
+
useState,
|
|
8
8
|
} from 'react';
|
|
9
9
|
import { Username } from '../../types';
|
|
10
10
|
import { EditorCacheValue } from '../useEditorCache';
|
|
11
11
|
import { getOrCreateEditor } from './getOrCreateEditor';
|
|
12
12
|
import { VZCodeContext } from '../VZCodeContext';
|
|
13
13
|
import { InteractRule } from '@replit/codemirror-interact';
|
|
14
|
+
import { EditorView } from 'codemirror'; // Import EditorView
|
|
15
|
+
import { Diagnostic } from '@codemirror/lint'; // Import Diagnostic
|
|
14
16
|
import './style.scss';
|
|
15
17
|
|
|
16
18
|
// The path in the ShareDB document where the files live.
|
|
@@ -18,12 +20,14 @@ const filesPath = ['files'];
|
|
|
18
20
|
|
|
19
21
|
export const CodeEditor = ({
|
|
20
22
|
customInteractRules,
|
|
21
|
-
allowGlobals,
|
|
22
23
|
aiCopilotEndpoint,
|
|
24
|
+
esLintSource,
|
|
23
25
|
}: {
|
|
24
26
|
customInteractRules?: Array<InteractRule>;
|
|
25
|
-
allowGlobals: boolean;
|
|
26
27
|
aiCopilotEndpoint?: string;
|
|
28
|
+
esLintSource: (
|
|
29
|
+
view: EditorView,
|
|
30
|
+
) => Promise<readonly Diagnostic[]>;
|
|
27
31
|
}) => {
|
|
28
32
|
const {
|
|
29
33
|
activePane,
|
|
@@ -36,7 +40,6 @@ export const CodeEditor = ({
|
|
|
36
40
|
editorCache,
|
|
37
41
|
editorWantsFocus,
|
|
38
42
|
editorNoLongerWantsFocus,
|
|
39
|
-
typeScriptWorker,
|
|
40
43
|
theme,
|
|
41
44
|
codeEditorRef,
|
|
42
45
|
enableAutoFollow,
|
|
@@ -81,11 +84,17 @@ export const CodeEditor = ({
|
|
|
81
84
|
enableAutoFollowRef.current = enableAutoFollow;
|
|
82
85
|
}, [enableAutoFollow]);
|
|
83
86
|
|
|
87
|
+
// State to hold the editor cache value
|
|
88
|
+
const [editorCacheValue, setEditorCacheValue] =
|
|
89
|
+
useState<EditorCacheValue | null>(null);
|
|
90
|
+
|
|
84
91
|
// Get the editor corresponding to the active file.
|
|
85
92
|
// Looks in `editorCache` first, and if not found, creates a new editor.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
let isMounted = true;
|
|
95
|
+
|
|
96
|
+
const initEditor = async () => {
|
|
97
|
+
const editor = await getOrCreateEditor({
|
|
89
98
|
fileId: activePane.activeFileId,
|
|
90
99
|
shareDBDoc,
|
|
91
100
|
content,
|
|
@@ -96,27 +105,36 @@ export const CodeEditor = ({
|
|
|
96
105
|
onInteract,
|
|
97
106
|
editorCache,
|
|
98
107
|
usernameRef,
|
|
99
|
-
typeScriptWorker,
|
|
100
108
|
customInteractRules,
|
|
101
|
-
allowGlobals,
|
|
102
109
|
enableAutoFollowRef,
|
|
103
110
|
openTab,
|
|
104
111
|
aiCopilotEndpoint,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
112
|
+
esLintSource,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (isMounted) {
|
|
116
|
+
setEditorCacheValue(editor);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
initEditor();
|
|
121
|
+
|
|
122
|
+
return () => {
|
|
123
|
+
isMounted = false;
|
|
124
|
+
};
|
|
125
|
+
}, [
|
|
126
|
+
activePane,
|
|
127
|
+
shareDBDoc,
|
|
128
|
+
filesPath,
|
|
129
|
+
localPresence,
|
|
130
|
+
docPresence,
|
|
131
|
+
theme,
|
|
132
|
+
onInteract,
|
|
133
|
+
editorCache,
|
|
134
|
+
usernameRef,
|
|
135
|
+
aiCopilotEndpoint,
|
|
136
|
+
esLintSource,
|
|
137
|
+
]);
|
|
120
138
|
|
|
121
139
|
// Every time the active file switches from one file to another,
|
|
122
140
|
// the editor corresponding to the old file is removed from the DOM,
|
|
@@ -125,6 +143,7 @@ export const CodeEditor = ({
|
|
|
125
143
|
// Guard against cases where page is still loading.
|
|
126
144
|
if (!codeEditorRef.current) return;
|
|
127
145
|
if (!content) return;
|
|
146
|
+
if (!editorCacheValue) return; // Guard against null editorCacheValue
|
|
128
147
|
// if (openSplitPane) return;
|
|
129
148
|
|
|
130
149
|
// Add the editor and apply the prior scroll position to the DOM.
|
|
@@ -138,17 +157,24 @@ export const CodeEditor = ({
|
|
|
138
157
|
return () => {
|
|
139
158
|
// Remove the old editor from the DOM and store the current scroll position.
|
|
140
159
|
// This happens every time `activeFileId` changes.
|
|
141
|
-
|
|
142
|
-
editorCacheValue
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
160
|
+
if (
|
|
161
|
+
editorCacheValue &&
|
|
162
|
+
codeEditorRef.current?.contains(
|
|
163
|
+
editorCacheValue.editor.dom,
|
|
164
|
+
)
|
|
165
|
+
) {
|
|
166
|
+
editorCacheValue.scrollPosition =
|
|
167
|
+
editorCacheValue.editor.scrollDOM.scrollTop;
|
|
168
|
+
codeEditorRef.current.removeChild(
|
|
169
|
+
editorCacheValue.editor.dom,
|
|
170
|
+
);
|
|
171
|
+
}
|
|
146
172
|
};
|
|
147
173
|
}, [shareDBDoc, editorCacheValue]);
|
|
148
174
|
|
|
149
175
|
// Focus the editor
|
|
150
176
|
useEffect(() => {
|
|
151
|
-
if (editorWantsFocus) {
|
|
177
|
+
if (editorWantsFocus && editorCacheValue) {
|
|
152
178
|
editorCacheValue.editor.focus();
|
|
153
179
|
editorNoLongerWantsFocus();
|
|
154
180
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createDefaultMapFromCDN,
|
|
3
|
+
createSystem,
|
|
4
|
+
createVirtualTypeScriptEnvironment,
|
|
5
|
+
} from '@typescript/vfs';
|
|
6
|
+
import ts from 'typescript';
|
|
7
|
+
import * as Comlink from 'comlink';
|
|
8
|
+
|
|
9
|
+
// When importing this module, typescript says that it "cannot find the module or its corresponding type declarations"
|
|
10
|
+
// However, when this file is used as a web worker, no error occurs.
|
|
11
|
+
// As a result, this error is suppressed to avoid future confusion.
|
|
12
|
+
// @ts-expect-error
|
|
13
|
+
import { createWorker } from '@valtown/codemirror-ts/worker';
|
|
14
|
+
|
|
15
|
+
Comlink.expose(
|
|
16
|
+
createWorker(async function () {
|
|
17
|
+
const fsMap = await createDefaultMapFromCDN(
|
|
18
|
+
{ target: ts.ScriptTarget.ES2022 },
|
|
19
|
+
'3.7.3',
|
|
20
|
+
false,
|
|
21
|
+
ts,
|
|
22
|
+
);
|
|
23
|
+
const system = createSystem(fsMap);
|
|
24
|
+
const compilerOpts = {};
|
|
25
|
+
return createVirtualTypeScriptEnvironment(
|
|
26
|
+
system,
|
|
27
|
+
[],
|
|
28
|
+
ts,
|
|
29
|
+
compilerOpts,
|
|
30
|
+
);
|
|
31
|
+
}),
|
|
32
|
+
);
|