vzcode 2.0.0 → 2.3.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.
Files changed (218) hide show
  1. package/dist/assets/{buildWorker-Dsx6rOdK.js → buildWorker-wLkQ0yz1.js} +64 -64
  2. package/dist/assets/{index-BM8tDh6M.css → index-BoFeK4GL.css} +1 -1
  3. package/dist/assets/{index-BgqNq-ww.js → index-DuUjtrt6.js} +107 -107
  4. package/dist/assets/{worker-BeBZGG1n.js → worker-DHxSPM7N.js} +78 -78
  5. package/dist/cli.js +113 -0
  6. package/dist/index.html +2 -2
  7. package/{src/ot.ts → dist/ot.js} +2 -14
  8. package/{src/randomId.ts → dist/randomId.js} +5 -6
  9. package/dist/runCode.js +20 -0
  10. package/dist/server/aiChatHandler/aiEditing.js +89 -0
  11. package/dist/server/aiChatHandler/chatOperations.js +360 -0
  12. package/dist/server/aiChatHandler/errorHandling.js +49 -0
  13. package/dist/server/aiChatHandler/index.js +112 -0
  14. package/dist/server/aiChatHandler/llmStreaming.js +284 -0
  15. package/dist/server/aiChatHandler/validation.js +19 -0
  16. package/dist/server/computeInitialDocument.js +146 -0
  17. package/{src/server/config.ts → dist/server/config.js} +4 -7
  18. package/{src/server/featureFlags.ts → dist/server/featureFlags.js} +0 -3
  19. package/dist/server/generateAIResponse.js +129 -0
  20. package/dist/server/handleAIAssist.js +39 -0
  21. package/dist/server/handleAICopilot.js +81 -0
  22. package/dist/server/index.js +297 -0
  23. package/dist/server/livekit.js +17 -0
  24. package/dist/server/prettier.js +90 -0
  25. package/{src/server/setupEnv.ts → dist/server/setupEnv.js} +1 -2
  26. package/dist/submitOperation.js +14 -0
  27. package/dist/types.js +1 -0
  28. package/dist/utils/fileDiff.js +66 -0
  29. package/package.json +23 -22
  30. package/src/client/AIAssist/AIAssistCodeMirrorKeyMap.ts +0 -42
  31. package/src/client/AIAssist/AIAssistWidget/index.tsx +0 -135
  32. package/src/client/AIAssist/AIAssistWidget/style.scss +0 -47
  33. package/src/client/AIAssist/Spinner.jsx +0 -76
  34. package/src/client/AIAssist/formatFile.ts +0 -27
  35. package/src/client/AIAssist/generateFilesContext.ts +0 -25
  36. package/src/client/AIAssist/index.ts +0 -2
  37. package/src/client/AIAssist/startAIAssist.ts +0 -95
  38. package/src/client/App/index.tsx +0 -153
  39. package/src/client/App/style.scss +0 -82
  40. package/src/client/App/usePending.ts +0 -51
  41. package/src/client/App/useShareDB.ts +0 -161
  42. package/src/client/CodeEditor/Copilot/index.ts +0 -74
  43. package/src/client/CodeEditor/InteractiveWidgets/boolToggler.ts +0 -12
  44. package/src/client/CodeEditor/InteractiveWidgets/colorPicker.ts +0 -68
  45. package/src/client/CodeEditor/InteractiveWidgets/colorsInTextPlugin.ts +0 -174
  46. package/src/client/CodeEditor/InteractiveWidgets/highlightWidgets.ts +0 -79
  47. package/src/client/CodeEditor/InteractiveWidgets/index.ts +0 -44
  48. package/src/client/CodeEditor/InteractiveWidgets/markdownCheckboxToggler.ts +0 -12
  49. package/src/client/CodeEditor/InteractiveWidgets/numberDragger.ts +0 -20
  50. package/src/client/CodeEditor/InteractiveWidgets/rotateWidget.ts +0 -143
  51. package/src/client/CodeEditor/InteractiveWidgets/urlClicker.test.ts +0 -48
  52. package/src/client/CodeEditor/InteractiveWidgets/urlClicker.ts +0 -12
  53. package/src/client/CodeEditor/InteractiveWidgets/vec2Slider.ts +0 -25
  54. package/src/client/CodeEditor/basicSetup.ts +0 -73
  55. package/src/client/CodeEditor/getOrCreateEditor.tsx +0 -615
  56. package/src/client/CodeEditor/index.tsx +0 -202
  57. package/src/client/CodeEditor/json1PresenceBroadcast.ts +0 -41
  58. package/src/client/CodeEditor/json1PresenceDisplay.ts +0 -350
  59. package/src/client/CodeEditor/rainbowBrackets.ts +0 -122
  60. package/src/client/CodeEditor/style.scss +0 -156
  61. package/src/client/CodeEditor/typescriptExtension/worker.ts +0 -32
  62. package/src/client/CodeErrorOverlay/index.tsx +0 -77
  63. package/src/client/CodeErrorOverlay/style.scss +0 -33
  64. package/src/client/Fonts/fonts.ts +0 -8
  65. package/src/client/Icons/AdjustmentSVG.tsx +0 -19
  66. package/src/client/Icons/BugSVG.tsx +0 -20
  67. package/src/client/Icons/CloseSVG.tsx +0 -19
  68. package/src/client/Icons/CssSVG.tsx +0 -16
  69. package/src/client/Icons/DirectoryArrowSVG.tsx +0 -19
  70. package/src/client/Icons/EditSVG.tsx +0 -19
  71. package/src/client/Icons/FileSVG.tsx +0 -19
  72. package/src/client/Icons/FolderSVG.tsx +0 -20
  73. package/src/client/Icons/GearSVG.tsx +0 -16
  74. package/src/client/Icons/HtmlSVG.tsx +0 -16
  75. package/src/client/Icons/JavaScriptSVG.tsx +0 -16
  76. package/src/client/Icons/JsonSVG.tsx +0 -16
  77. package/src/client/Icons/MarkdownSVG.tsx +0 -16
  78. package/src/client/Icons/MicSVG.tsx +0 -25
  79. package/src/client/Icons/NewSVG.tsx +0 -19
  80. package/src/client/Icons/PinSVG.tsx +0 -14
  81. package/src/client/Icons/PlaySVG.tsx +0 -16
  82. package/src/client/Icons/QuestionMarkSVG.tsx +0 -18
  83. package/src/client/Icons/ReactSVG.tsx +0 -16
  84. package/src/client/Icons/SearchSVG.tsx +0 -20
  85. package/src/client/Icons/SparklesSVG.tsx +0 -23
  86. package/src/client/Icons/SplitEditorSVG.tsx +0 -34
  87. package/src/client/Icons/StopSVG.tsx +0 -15
  88. package/src/client/Icons/SvelteSVG.tsx +0 -16
  89. package/src/client/Icons/TrashSVG.tsx +0 -19
  90. package/src/client/Icons/TypeScriptSVG.tsx +0 -16
  91. package/src/client/Icons/index.tsx +0 -24
  92. package/src/client/ImageViewer/index.tsx +0 -91
  93. package/src/client/ImageViewer/style.scss +0 -41
  94. package/src/client/PresenceNotifications/PresenceNotifications.test.ts +0 -134
  95. package/src/client/PresenceNotifications/index.tsx +0 -158
  96. package/src/client/PresenceNotifications/style.scss +0 -17
  97. package/src/client/RunCodeWidget/index.tsx +0 -117
  98. package/src/client/RunCodeWidget/style.scss +0 -24
  99. package/src/client/SplitPaneResizeContext.tsx +0 -159
  100. package/src/client/TabList/Tab.tsx +0 -73
  101. package/src/client/TabList/index.tsx +0 -35
  102. package/src/client/TabList/style.scss +0 -51
  103. package/src/client/VZCodeContext/index.tsx +0 -29
  104. package/src/client/VZCodeContext/types.ts +0 -249
  105. package/src/client/VZCodeContext/useVZCodeState.ts +0 -584
  106. package/src/client/VZKeyboardShortcutsDoc.tsx +0 -148
  107. package/src/client/VZLeft.tsx +0 -28
  108. package/src/client/VZMiddle.tsx +0 -172
  109. package/src/client/VZResizer/index.tsx +0 -128
  110. package/src/client/VZResizer/styles.scss +0 -33
  111. package/src/client/VZRight.tsx +0 -113
  112. package/src/client/VZSettings.tsx +0 -275
  113. package/src/client/VZSidebar/AIChat/ChatInput.tsx +0 -196
  114. package/src/client/VZSidebar/AIChat/DiffView.scss +0 -136
  115. package/src/client/VZSidebar/AIChat/DiffView.tsx +0 -176
  116. package/src/client/VZSidebar/AIChat/Message.tsx +0 -143
  117. package/src/client/VZSidebar/AIChat/MessageList.tsx +0 -205
  118. package/src/client/VZSidebar/AIChat/StreamingMessage.tsx +0 -35
  119. package/src/client/VZSidebar/AIChat/ThinkingScratchpad.tsx +0 -156
  120. package/src/client/VZSidebar/AIChat/TypingIndicator.tsx +0 -19
  121. package/src/client/VZSidebar/AIChat/index.tsx +0 -273
  122. package/src/client/VZSidebar/AIChat/styles.scss +0 -627
  123. package/src/client/VZSidebar/CreateDirModal.tsx +0 -111
  124. package/src/client/VZSidebar/CreateFileModal.tsx +0 -111
  125. package/src/client/VZSidebar/DeleteConfirmationModal.tsx +0 -76
  126. package/src/client/VZSidebar/DirectoryListing.tsx +0 -89
  127. package/src/client/VZSidebar/EmptyState.tsx +0 -11
  128. package/src/client/VZSidebar/FileListing.tsx +0 -91
  129. package/src/client/VZSidebar/FileTypeIcon.tsx +0 -49
  130. package/src/client/VZSidebar/Item.tsx +0 -237
  131. package/src/client/VZSidebar/Listing.tsx +0 -47
  132. package/src/client/VZSidebar/Search.tsx +0 -527
  133. package/src/client/VZSidebar/VisualEditor.tsx +0 -295
  134. package/src/client/VZSidebar/VoiceChatModal.tsx +0 -121
  135. package/src/client/VZSidebar/aiCopyPaste.ts +0 -199
  136. package/src/client/VZSidebar/index.tsx +0 -728
  137. package/src/client/VZSidebar/styles.scss +0 -612
  138. package/src/client/VZSidebar/useDragAndDrop.tsx +0 -408
  139. package/src/client/bootstrap.ts +0 -26
  140. package/src/client/buildWorker.ts +0 -3
  141. package/src/client/featureFlags.ts +0 -8
  142. package/src/client/generateRequestId.ts +0 -6
  143. package/src/client/getFileTree.ts +0 -53
  144. package/src/client/index.ts +0 -19
  145. package/src/client/main.jsx +0 -10
  146. package/src/client/presenceColor.ts +0 -8
  147. package/src/client/shouldTriggerRun.ts +0 -31
  148. package/src/client/sortFileTree.ts +0 -21
  149. package/src/client/tabsSearchParameters.test.ts +0 -79
  150. package/src/client/tabsSearchParameters.ts +0 -137
  151. package/src/client/themes/index.ts +0 -7
  152. package/src/client/themes/themes.ts +0 -77
  153. package/src/client/themes/uiwImports.ts +0 -32
  154. package/src/client/themes/useDynamicTheme.ts +0 -29
  155. package/src/client/themes/vizhubTheme/colors.ts +0 -80
  156. package/src/client/themes/vizhubTheme/index.ts +0 -193
  157. package/src/client/useActions.ts +0 -288
  158. package/src/client/useESLint/index.ts +0 -72
  159. package/src/client/useESLint/worker.ts +0 -113
  160. package/src/client/useEditorCache.ts +0 -35
  161. package/src/client/useFileCRUD.ts +0 -228
  162. package/src/client/useKeyboardShortcuts.ts +0 -451
  163. package/src/client/useOpenDirectories.ts +0 -99
  164. package/src/client/usePresenceAutoFollow.ts +0 -85
  165. package/src/client/usePrettier/index.ts +0 -178
  166. package/src/client/usePrettier/worker.ts +0 -109
  167. package/src/client/useRunCode.tsx +0 -15
  168. package/src/client/useRuntimeError.ts +0 -32
  169. package/src/client/useSubmitOperation.ts +0 -15
  170. package/src/client/useURLSync.ts +0 -137
  171. package/src/client/usernameLocalStorage.ts +0 -43
  172. package/src/client/utils/fileExtension.ts +0 -10
  173. package/src/client/utils/isImageFile.ts +0 -12
  174. package/src/client/vzReducer/aiChatReducer.ts +0 -44
  175. package/src/client/vzReducer/closeTabReducer.test.ts +0 -205
  176. package/src/client/vzReducer/closeTabsReducer.ts +0 -96
  177. package/src/client/vzReducer/createInitialState.ts +0 -38
  178. package/src/client/vzReducer/editorNoLongerWantsFocusReducer.ts +0 -9
  179. package/src/client/vzReducer/findPane.ts +0 -19
  180. package/src/client/vzReducer/index.ts +0 -250
  181. package/src/client/vzReducer/openTabReducer.test.ts +0 -127
  182. package/src/client/vzReducer/openTabReducer.ts +0 -74
  183. package/src/client/vzReducer/searchReducer.test.ts +0 -292
  184. package/src/client/vzReducer/searchReducer.ts +0 -181
  185. package/src/client/vzReducer/setActiveFileIdReducer.ts +0 -28
  186. package/src/client/vzReducer/setActiveFileLeftRightReducer.ts +0 -76
  187. package/src/client/vzReducer/setIsDocOpenReducer.ts +0 -9
  188. package/src/client/vzReducer/setIsSettingsOpenReducer.ts +0 -9
  189. package/src/client/vzReducer/setThemeReducer.ts +0 -9
  190. package/src/client/vzReducer/setUsernameReducer.ts +0 -9
  191. package/src/client/vzReducer/splitCurrentPaneReducer.ts +0 -66
  192. package/src/client/vzReducer/toggleAutoFollowReducer.ts +0 -12
  193. package/src/client/vzReducer/updatePane.ts +0 -40
  194. package/src/client/vzReducer/updatePresenceIndicatorReducer.ts +0 -30
  195. package/src/client/vzReducer/visualEditorReducer.ts +0 -9
  196. package/src/reactRouterExports.ts +0 -15
  197. package/src/runCode.ts +0 -27
  198. package/src/server/aiChatHandler/aiEditing.ts +0 -152
  199. package/src/server/aiChatHandler/chatOperations.ts +0 -510
  200. package/src/server/aiChatHandler/errorHandling.ts +0 -66
  201. package/src/server/aiChatHandler/index.ts +0 -200
  202. package/src/server/aiChatHandler/llmStreaming.ts +0 -419
  203. package/src/server/aiChatHandler/undoHandler.ts +0 -97
  204. package/src/server/aiChatHandler/validation.ts +0 -24
  205. package/src/server/computeInitialDocument.ts +0 -220
  206. package/src/server/generateAIResponse.ts +0 -188
  207. package/src/server/handleAIAssist.ts +0 -53
  208. package/src/server/handleAIChatUndo.ts +0 -2
  209. package/src/server/handleAICopilot.ts +0 -97
  210. package/src/server/index.ts +0 -388
  211. package/src/server/livekit.ts +0 -24
  212. package/src/server/prettier.ts +0 -115
  213. package/src/submitOperation.ts +0 -25
  214. package/src/types.ts +0 -205
  215. package/src/utils/fileDiff.ts +0 -117
  216. package/src/vite-env.d.ts +0 -10
  217. /package/{src/server/handleAIChatMessage.ts → dist/server/handleAIChatMessage.js} +0 -0
  218. /package/{src/server/isDirectory.ts → dist/server/isDirectory.js} +0 -0
@@ -1,228 +0,0 @@
1
- import { useCallback } from 'react';
2
- import { FileTreePath } from '../types';
3
- import { VizFileId, VizContent } from '@vizhub/viz-types';
4
- import { randomId } from '../randomId';
5
- import { EditorCache } from './useEditorCache';
6
- import { getFileExtension } from './utils/fileExtension';
7
- import { getLanguageExtension } from './CodeEditor/getOrCreateEditor';
8
- import { editorCacheKey } from './useEditorCache';
9
-
10
- // CRUD operations for files and directories
11
- // CRUD = Create, Read, Update, Delete
12
- export const useFileCRUD = ({
13
- submitOperation,
14
- closeTabs,
15
- openTab,
16
- editorCache,
17
- content,
18
- }: {
19
- submitOperation: (
20
- operation: (document: VizContent) => VizContent,
21
- ) => void;
22
- closeTabs: (idsToDelete: Array<VizFileId>) => void;
23
- openTab: ({
24
- fileId,
25
- isTransient,
26
- }: {
27
- fileId: VizFileId;
28
- isTransient: boolean;
29
- }) => void;
30
- editorCache: EditorCache;
31
- content: VizContent;
32
- }) => {
33
- // Create a new file
34
- const createFile = useCallback(
35
- (name: string, text = '') => {
36
- if (name) {
37
- const fileId: VizFileId = randomId();
38
- submitOperation((document: VizContent) => ({
39
- ...document,
40
- files: {
41
- ...document.files,
42
- [fileId]: { name, text },
43
- },
44
- }));
45
- // When a new file is created, open it in a new tab
46
- // and focus the editor on it.
47
- openTab({ fileId, isTransient: false });
48
- }
49
- },
50
- [submitOperation],
51
- );
52
-
53
- const createDirectory = useCallback(
54
- (name: string, text = null) => {
55
- if (name) {
56
- name += '/';
57
- const fileId: VizFileId = randomId();
58
- submitOperation((document: VizContent) => ({
59
- ...document,
60
- files: {
61
- ...document.files,
62
- [fileId]: { name, text },
63
- },
64
- }));
65
- }
66
- },
67
- [submitOperation],
68
- );
69
-
70
- // Called when a file in the sidebar is renamed.
71
- const renameFile = useCallback(
72
- (fileId: VizFileId, newName: string) => {
73
- submitOperation((document: VizContent) => ({
74
- ...document,
75
- files: {
76
- ...document.files,
77
- [fileId]: {
78
- ...document.files[fileId],
79
- name:
80
- document.files[fileId].name.substring(
81
- 0,
82
- document.files[fileId].name.lastIndexOf(
83
- '/',
84
- ) + 1,
85
- ) + newName,
86
- },
87
- },
88
- }));
89
-
90
- const oldName = content.files[fileId].name;
91
- const oldExtension = getFileExtension(oldName);
92
-
93
- const newExtension = getFileExtension(newName);
94
-
95
- const didExtensionChange =
96
- newExtension !== oldExtension;
97
- if (didExtensionChange) {
98
- // Update the language compartment of the corresponding CodeMirror editor
99
- // with the new language, based on the new extension, only if it changed.
100
- // Search through all cached editors for this file ID
101
- for (const [
102
- cacheKey,
103
- cachedEditor,
104
- ] of editorCache.entries()) {
105
- // Check if this cache entry is for the current file
106
- if (cacheKey.startsWith(fileId + '|')) {
107
- if (
108
- cachedEditor &&
109
- cachedEditor.languageCompartment
110
- ) {
111
- const newLanguageExtension =
112
- getLanguageExtension(newExtension);
113
-
114
- // Reconfigure the language compartment with the new language extension
115
- cachedEditor.editor.dispatch({
116
- effects:
117
- cachedEditor.languageCompartment.reconfigure(
118
- newLanguageExtension
119
- ? [newLanguageExtension]
120
- : [],
121
- ),
122
- });
123
- // Continue to update all instances of this file in different panes
124
- }
125
- }
126
- }
127
- }
128
- },
129
- [submitOperation],
130
- );
131
-
132
- // Renames a directory
133
- const renameDirectory = useCallback(
134
- (
135
- path: FileTreePath,
136
- oldName: string,
137
- newName: string,
138
- ) => {
139
- submitOperation((document: VizContent) => {
140
- const updatedFiles = Object.keys(
141
- document.files,
142
- ).reduce((acc, key) => {
143
- const file = document.files[key];
144
- const fileName = file.name;
145
- //See if it's actually in directory
146
- if (fileName.includes(path + '/')) {
147
- //Create New Name for System
148
- const pathPart = fileName.substring(
149
- 0,
150
- fileName.indexOf(path) + path.length,
151
- );
152
- const oldNamePos =
153
- pathPart.lastIndexOf(oldName);
154
- const fileNewName =
155
- fileName.substring(0, oldNamePos) +
156
- newName +
157
- fileName.substring(
158
- oldNamePos + oldName.length,
159
- );
160
- //Return with new names
161
- acc[key] = { ...file, name: fileNewName };
162
- } else {
163
- acc[key] = file;
164
- }
165
- return acc;
166
- }, {});
167
-
168
- return { ...document, files: updatedFiles };
169
- });
170
- },
171
- [submitOperation],
172
- );
173
-
174
- // Deletes a file
175
- const deleteFile = useCallback(
176
- (fileId: VizFileId) => {
177
- closeTabs([fileId]);
178
- submitOperation((document) => {
179
- const updatedFiles = { ...document.files };
180
- delete updatedFiles[fileId];
181
- return { ...document, files: updatedFiles };
182
- });
183
- },
184
- [submitOperation, closeTabs],
185
- );
186
-
187
- // Deletes a directory and all files within it
188
- const deleteDirectory = useCallback(
189
- (path: FileTreePath) => {
190
- const tabsToClose: Array<VizFileId> = [];
191
- submitOperation((document: VizContent) => {
192
- const updatedFiles = { ...document.files };
193
- for (const key in updatedFiles) {
194
- if (updatedFiles[key].name.includes(path + '/')) {
195
- tabsToClose.push(key);
196
- delete updatedFiles[key];
197
- }
198
- }
199
- return { ...document, files: updatedFiles };
200
- });
201
- closeTabs(tabsToClose);
202
- },
203
- [submitOperation, closeTabs],
204
- );
205
-
206
- // Deletes all files
207
- const deleteAllFiles = useCallback(() => {
208
- const tabsToClose: Array<VizFileId> = [];
209
- submitOperation((document: VizContent) => {
210
- // Collect all file IDs for closing tabs
211
- for (const fileId in document.files) {
212
- tabsToClose.push(fileId);
213
- }
214
- return { ...document, files: {} };
215
- });
216
- closeTabs(tabsToClose);
217
- }, [submitOperation, closeTabs]);
218
-
219
- return {
220
- createFile,
221
- renameFile,
222
- deleteFile,
223
- createDirectory,
224
- renameDirectory,
225
- deleteDirectory,
226
- deleteAllFiles,
227
- };
228
- };
@@ -1,451 +0,0 @@
1
- import { useContext, useEffect } from 'react';
2
- import { shouldTriggerRun } from './shouldTriggerRun';
3
- import { syntaxTree } from '@codemirror/language';
4
- import { SyntaxNode, SyntaxNodeRef } from '@lezer/common';
5
- import { EditorView } from '@codemirror/view';
6
- import { EditorState } from '@codemirror/state';
7
- import { VizFileId } from '@vizhub/viz-types';
8
- import { PaneId } from '../types';
9
- import { editorCacheKey } from './useEditorCache';
10
-
11
- /*
12
- The following is a helpful resource for the following Code Mirror Syntax Tree methods below
13
- https://lezer.codemirror.net/docs/ref/#common
14
- */
15
-
16
- // Store the element in the current editor DOM to highlight, indicating a potential jump to definition is possible
17
- let activeJumpingElement: HTMLSpanElement = null;
18
-
19
- // Store the syntax node representing the destination within the syntax tree
20
- let definingNode: SyntaxNode = null;
21
-
22
- // Example nesting types for the specific language to find level in the syntax tree
23
- const nestingTypes = new Set<string>([
24
- 'FunctionDeclaration',
25
- 'ClassDeclaration',
26
- 'MethodDeclaration',
27
- 'Block',
28
- 'IfStatement',
29
- 'ForStatement',
30
- 'WhileStatement',
31
- 'SwitchStatement',
32
- 'TryStatement',
33
- 'CatchClause',
34
- 'WithStatement',
35
- 'ArrowFunction',
36
- 'ImportGroup',
37
- ]);
38
-
39
- // Example declaration types for the specific language to find definitions in the syntax tree
40
- const declarationTypes = new Set<string>([
41
- 'VariableDeclaration',
42
- 'FunctionDeclaration',
43
- 'ClassDeclaration',
44
- 'MethodDeclaration',
45
- 'PropertyDeclaration',
46
- 'ImportDeclaration',
47
- 'ExportDeclaration',
48
- 'CallExpression',
49
- 'ArrayPattern',
50
- 'ObjectPattern',
51
- 'PatternProperty',
52
- 'ArgList',
53
- 'TypeArgList',
54
- 'ParamList',
55
- 'ForOfSpec',
56
- ]);
57
-
58
- function getIdentifierContext(
59
- identifier: SyntaxNode,
60
- ): number {
61
- let current: SyntaxNode = identifier;
62
- let levels: number = 0;
63
-
64
- // Traverse up the tree to find the total depth, only counting valid nesting types
65
- while (current && current.type) {
66
- const parentType: string = current.type.name;
67
-
68
- if (nestingTypes.has(parentType)) {
69
- levels++;
70
- }
71
-
72
- current = current.parent;
73
- }
74
-
75
- return levels;
76
- }
77
-
78
- function jumpToDefinition(
79
- editor: EditorView,
80
- node: SyntaxNode,
81
- ): SyntaxNode {
82
- const state: EditorState = editor.state;
83
- const definitions: Array<{
84
- identifier: SyntaxNode;
85
- context: number;
86
- }> = [];
87
-
88
- // From an identifier in the syntax tree, fetch the name and context to find closest defining syntax node
89
- const identifier: SyntaxNode = node;
90
- const identifierName: string = state.doc.sliceString(
91
- identifier.from,
92
- identifier.to,
93
- );
94
- const context: number = getIdentifierContext(identifier);
95
-
96
- if (identifier) {
97
- syntaxTree(state).iterate({
98
- enter(tree: SyntaxNodeRef) {
99
- // Traverse syntax tree to find positions of respective identifier definitions within context
100
- if (
101
- declarationTypes.has(tree.name) ||
102
- nestingTypes.has(tree.name)
103
- ) {
104
- const parent: SyntaxNode = tree.node;
105
-
106
- // Fetch a host of potential identifiers in an attempt to find the defining syntax node
107
- const children: Array<SyntaxNode> = [
108
- ...parent.getChildren('VariableDefinition'),
109
- ...parent.getChildren('PropertyDefinition'),
110
- ...parent.getChildren('PropertyName'),
111
- ...parent.getChildren('Identifier'),
112
- ];
113
-
114
- children.forEach((child: SyntaxNode) => {
115
- const name: string = state.doc.sliceString(
116
- child.from,
117
- child.to,
118
- );
119
-
120
- // Ensure no jump to self by comparing syntax node id's
121
- if (
122
- name === identifierName &&
123
- child.type.id !== identifier.type.id
124
- ) {
125
- definitions.push({
126
- identifier: child,
127
- context: getIdentifierContext(child),
128
- });
129
- }
130
- });
131
- }
132
- },
133
- });
134
-
135
- if (definitions.length > 0) {
136
- // Sort definitions by their context in the syntax tree
137
- definitions.sort((a, b) => a.context - b.context);
138
-
139
- let closestDefinition: SyntaxNode =
140
- definitions[0].identifier;
141
-
142
- for (let i = definitions.length - 1; i >= 0; i--) {
143
- if (definitions[i].context <= context) {
144
- closestDefinition = definitions[i].identifier;
145
- break;
146
- }
147
- }
148
-
149
- return closestDefinition;
150
- }
151
-
152
- return null;
153
- }
154
- }
155
-
156
- // Sidebar keyboard shortcuts in form Ctrl + Shift + <key>
157
- const sideBarKeyBoardMap = {
158
- E: 'files-icon',
159
- F: 'search-icon',
160
- K: 'shortcut-icon',
161
- B: 'bug-icon',
162
- S: 'settings-icon',
163
- N: 'new-file-icon',
164
- D: 'new-directory-icon',
165
- A: 'auto-focus-icon',
166
- };
167
-
168
- // This module implements the keyboard shortcuts
169
- // for the VZCode editor.
170
- // These include:
171
- // * Alt-w: Close the current tab
172
- // * Alt-n: Open the create file modal
173
- // * Alt-PageUp: Change the active tab to the previous one
174
- // * Alt-PageDown: Change the active tab to the next one
175
- // * Ctrl-s or Shift-Enter: Run the code and format it with Prettier
176
- // * Ctrl-Click: Jump to closest definition for a potential identifier
177
- export const useKeyboardShortcuts = ({
178
- closeTabs,
179
- activeFileId,
180
- activePaneId,
181
- handleOpenCreateFileModal,
182
- setActiveFileLeft,
183
- setActiveFileRight,
184
- toggleSearchFocused,
185
- runPrettierRef,
186
- runCodeRef,
187
- sidebarRef,
188
- editorCache,
189
- codeEditorRef,
190
- }: {
191
- closeTabs: (fileIds: VizFileId[]) => void;
192
- activeFileId: VizFileId | null;
193
- activePaneId: PaneId;
194
- handleOpenCreateFileModal: () => void;
195
- setActiveFileLeft: () => void;
196
- setActiveFileRight: () => void;
197
- toggleSearchFocused: () => void;
198
- runPrettierRef: React.MutableRefObject<() => void>;
199
- runCodeRef: React.MutableRefObject<() => void>;
200
- sidebarRef: React.RefObject<HTMLDivElement>;
201
- editorCache: Map<string, { editor: EditorView }>;
202
- codeEditorRef: React.RefObject<HTMLDivElement>;
203
- }) => {
204
- useEffect(() => {
205
- // This key is needed to look up the current editor in the editor cache.
206
- const cacheKey = editorCacheKey(
207
- activeFileId,
208
- activePaneId,
209
- );
210
-
211
- const handleKeyPress = (event: KeyboardEvent) => {
212
- if (shouldTriggerRun(event)) {
213
- event.preventDefault();
214
-
215
- // Run Prettier
216
- const runPrettier = runPrettierRef.current;
217
- if (runPrettier !== null) {
218
- runPrettier();
219
- }
220
-
221
- // Run the code
222
- const runCode = runCodeRef.current;
223
-
224
- if (runCode !== null) {
225
- runCode();
226
- }
227
- return;
228
- }
229
-
230
- if (event.ctrlKey && event.shiftKey) {
231
- // Handle keyboard shortcuts related to the side bar icons
232
- document
233
- .getElementById(sideBarKeyBoardMap[event.key])
234
- ?.click();
235
-
236
- // Ensure the search input is always focused
237
- if (event.key === 'F') {
238
- toggleSearchFocused();
239
- }
240
- } else if (event.ctrlKey && event.key === ',') {
241
- document
242
- .getElementById(sideBarKeyBoardMap['S'])
243
- ?.click();
244
- }
245
-
246
- if (event.ctrlKey === true) {
247
- // On holding CTRL key, search for a potential definition jump using mouse location
248
- document.addEventListener(
249
- 'mouseover',
250
- handleMouseOver,
251
- );
252
- }
253
-
254
- if (event.altKey === true) {
255
- // Alt-w: Close the current tab
256
- if (event.key === 'w') {
257
- // TODO clean this up so we can remove `activeFileId`
258
- // as a dependency
259
- // TODO closeActiveTab()
260
- if (activeFileId) {
261
- closeTabs([activeFileId]);
262
- }
263
- return;
264
- }
265
-
266
- // Alt-n: Open the create file modal
267
- if (event.key === 'n') {
268
- handleOpenCreateFileModal();
269
- return;
270
- }
271
-
272
- // Alt-PageUp: Change the active tab to the previous one
273
- if (event.key === 'PageUp') {
274
- setActiveFileLeft();
275
- return;
276
- }
277
-
278
- // Alt-PageDown: Change the active tab to the next one
279
- if (event.key === 'PageDown') {
280
- setActiveFileRight();
281
- return;
282
- }
283
-
284
- if (event.key === '1') {
285
- if (sidebarRef.current) {
286
- sidebarRef.current.focus();
287
- }
288
- }
289
-
290
- if (event.key === '2') {
291
- if (codeEditorRef.current) {
292
- codeEditorRef.current.focus();
293
- }
294
- }
295
- }
296
- };
297
-
298
- const resetActiveJumpingElement = (): void => {
299
- if (activeJumpingElement) {
300
- activeJumpingElement.style.cursor = 'initial';
301
- activeJumpingElement.style.textDecoration = 'none';
302
- activeJumpingElement = definingNode = null;
303
- }
304
-
305
- document.removeEventListener(
306
- 'mouseover',
307
- handleMouseOver,
308
- );
309
- document.removeEventListener(
310
- 'mousedown',
311
- jumpToDefinitionHandler,
312
- );
313
- };
314
-
315
- const jumpToDefinitionHandler = (
316
- event: MouseEvent,
317
- ): void => {
318
- // Ensure the current destination node is defined
319
- // and current cursor position matches highlighted element
320
- if (
321
- !definingNode ||
322
- (event.target as HTMLSpanElement) !==
323
- activeJumpingElement
324
- ) {
325
- return;
326
- }
327
-
328
- // Don't crash if no active file
329
- if (!activeFileId) {
330
- return;
331
- }
332
-
333
- // Move current cursor and center view in the editor to destination node
334
-
335
- const editor: EditorView =
336
- editorCache.get(cacheKey).editor;
337
- const closestDefinition: SyntaxNode = definingNode;
338
-
339
- editor.dispatch({
340
- selection: {
341
- anchor: closestDefinition.from,
342
- head: closestDefinition.to,
343
- },
344
- scrollIntoView: true,
345
- effects: EditorView.scrollIntoView(
346
- closestDefinition.from,
347
- {
348
- y: 'center',
349
- },
350
- ),
351
- });
352
-
353
- resetActiveJumpingElement();
354
- };
355
-
356
- const handleKeyRelease = (event: KeyboardEvent) => {
357
- // On releasing CTRL key, reset all active definition jumping elements and listeners
358
- if (!event.ctrlKey) {
359
- resetActiveJumpingElement();
360
- }
361
- };
362
-
363
- const handleMouseOver = (event: MouseEvent) => {
364
- if (!activeFileId) {
365
- return;
366
- }
367
-
368
- const editor: EditorView =
369
- editorCache.get(cacheKey).editor;
370
- const tree = syntaxTree(editor.state);
371
- const element = event.target as HTMLSpanElement;
372
-
373
- // Ensure the identifier element can be found and is within the current editor DOM
374
- if (
375
- element == null ||
376
- !editor.dom.contains(element)
377
- ) {
378
- return;
379
- }
380
-
381
- let position: number;
382
- try {
383
- position = editor.posAtDOM(element);
384
- } catch (error) {
385
- // Element is not within the current editor's document
386
- return;
387
- }
388
- const identifier: SyntaxNode = tree.resolveInner(
389
- position,
390
- 1,
391
- );
392
-
393
- // All valid identifiers must be span elements to find a potential defining jump in editor
394
- if (
395
- identifier &&
396
- element instanceof HTMLSpanElement
397
- ) {
398
- const potentialJump: SyntaxNode = jumpToDefinition(
399
- editor,
400
- identifier,
401
- );
402
-
403
- // Only allowing to jump to other definition nodes
404
- if (
405
- potentialJump &&
406
- identifier.type.id !== potentialJump.type.id
407
- ) {
408
- if (activeJumpingElement) {
409
- activeJumpingElement.style.cursor = 'initial';
410
- activeJumpingElement.style.textDecoration =
411
- 'none';
412
- }
413
-
414
- activeJumpingElement = element;
415
- definingNode = potentialJump;
416
-
417
- activeJumpingElement.style.cursor = 'pointer';
418
- activeJumpingElement.style.textDecoration =
419
- 'underline';
420
-
421
- // CTRL + Click: Jump to relative definition, which is removed on CTRL key release
422
- document.addEventListener(
423
- 'mousedown',
424
- jumpToDefinitionHandler,
425
- { once: true },
426
- );
427
- }
428
- }
429
- };
430
-
431
- document.addEventListener('keydown', handleKeyPress);
432
- document.addEventListener('keyup', handleKeyRelease);
433
-
434
- return () => {
435
- document.removeEventListener(
436
- 'keydown',
437
- handleKeyPress,
438
- );
439
- document.removeEventListener(
440
- 'keyup',
441
- handleKeyRelease,
442
- );
443
- };
444
- }, [
445
- handleOpenCreateFileModal,
446
- closeTabs,
447
- activeFileId,
448
- setActiveFileLeft,
449
- setActiveFileRight,
450
- ]);
451
- };