@finos/legend-application-pure-ide 6.2.14

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 (269) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +3 -0
  3. package/lib/application/LegendPureIDE.d.ts +26 -0
  4. package/lib/application/LegendPureIDE.d.ts.map +1 -0
  5. package/lib/application/LegendPureIDE.js +43 -0
  6. package/lib/application/LegendPureIDE.js.map +1 -0
  7. package/lib/application/LegendPureIDEApplicationConfig.d.ts +28 -0
  8. package/lib/application/LegendPureIDEApplicationConfig.d.ts.map +1 -0
  9. package/lib/application/LegendPureIDEApplicationConfig.js +30 -0
  10. package/lib/application/LegendPureIDEApplicationConfig.js.map +1 -0
  11. package/lib/application/LegendPureIDEPluginManager.d.ts +32 -0
  12. package/lib/application/LegendPureIDEPluginManager.d.ts.map +1 -0
  13. package/lib/application/LegendPureIDEPluginManager.js +46 -0
  14. package/lib/application/LegendPureIDEPluginManager.js.map +1 -0
  15. package/lib/components/Core_LegendPureIDEApplicationPlugin.d.ts +23 -0
  16. package/lib/components/Core_LegendPureIDEApplicationPlugin.d.ts.map +1 -0
  17. package/lib/components/Core_LegendPureIDEApplicationPlugin.js +29 -0
  18. package/lib/components/Core_LegendPureIDEApplicationPlugin.js.map +1 -0
  19. package/lib/components/LegendPureIDEApplication.d.ts +18 -0
  20. package/lib/components/LegendPureIDEApplication.d.ts.map +1 -0
  21. package/lib/components/LegendPureIDEApplication.js +21 -0
  22. package/lib/components/LegendPureIDEApplication.js.map +1 -0
  23. package/lib/components/LegendPureIDEBaseStoreProvider.d.ts +23 -0
  24. package/lib/components/LegendPureIDEBaseStoreProvider.d.ts.map +1 -0
  25. package/lib/components/LegendPureIDEBaseStoreProvider.js +30 -0
  26. package/lib/components/LegendPureIDEBaseStoreProvider.js.map +1 -0
  27. package/lib/components/editor/ActivityBar.d.ts +20 -0
  28. package/lib/components/editor/ActivityBar.d.ts.map +1 -0
  29. package/lib/components/editor/ActivityBar.js +41 -0
  30. package/lib/components/editor/ActivityBar.js.map +1 -0
  31. package/lib/components/editor/Editor.d.ts +18 -0
  32. package/lib/components/editor/Editor.d.ts.map +1 -0
  33. package/lib/components/editor/Editor.js +80 -0
  34. package/lib/components/editor/Editor.js.map +1 -0
  35. package/lib/components/editor/EditorStoreProvider.d.ts +22 -0
  36. package/lib/components/editor/EditorStoreProvider.d.ts.map +1 -0
  37. package/lib/components/editor/EditorStoreProvider.js +32 -0
  38. package/lib/components/editor/EditorStoreProvider.js.map +1 -0
  39. package/lib/components/editor/StatusBar.d.ts +22 -0
  40. package/lib/components/editor/StatusBar.d.ts.map +1 -0
  41. package/lib/components/editor/StatusBar.js +39 -0
  42. package/lib/components/editor/StatusBar.js.map +1 -0
  43. package/lib/components/editor/aux-panel/AuxiliaryPanel.d.ts +20 -0
  44. package/lib/components/editor/aux-panel/AuxiliaryPanel.d.ts.map +1 -0
  45. package/lib/components/editor/aux-panel/AuxiliaryPanel.js +65 -0
  46. package/lib/components/editor/aux-panel/AuxiliaryPanel.js.map +1 -0
  47. package/lib/components/editor/aux-panel/ConsolePanel.d.ts +20 -0
  48. package/lib/components/editor/aux-panel/ConsolePanel.d.ts.map +1 -0
  49. package/lib/components/editor/aux-panel/ConsolePanel.js +24 -0
  50. package/lib/components/editor/aux-panel/ConsolePanel.js.map +1 -0
  51. package/lib/components/editor/aux-panel/SearchPanel.d.ts +20 -0
  52. package/lib/components/editor/aux-panel/SearchPanel.d.ts.map +1 -0
  53. package/lib/components/editor/aux-panel/SearchPanel.js +90 -0
  54. package/lib/components/editor/aux-panel/SearchPanel.js.map +1 -0
  55. package/lib/components/editor/aux-panel/TestRunnerPanel.d.ts +20 -0
  56. package/lib/components/editor/aux-panel/TestRunnerPanel.d.ts.map +1 -0
  57. package/lib/components/editor/aux-panel/TestRunnerPanel.js +151 -0
  58. package/lib/components/editor/aux-panel/TestRunnerPanel.js.map +1 -0
  59. package/lib/components/editor/command-center/CreateNewDirectoryCommand.d.ts +20 -0
  60. package/lib/components/editor/command-center/CreateNewDirectoryCommand.d.ts.map +1 -0
  61. package/lib/components/editor/command-center/CreateNewDirectoryCommand.js +48 -0
  62. package/lib/components/editor/command-center/CreateNewDirectoryCommand.js.map +1 -0
  63. package/lib/components/editor/command-center/CreateNewFileCommand.d.ts +20 -0
  64. package/lib/components/editor/command-center/CreateNewFileCommand.d.ts.map +1 -0
  65. package/lib/components/editor/command-center/CreateNewFileCommand.js +48 -0
  66. package/lib/components/editor/command-center/CreateNewFileCommand.js.map +1 -0
  67. package/lib/components/editor/command-center/FileSearchCommand.d.ts +20 -0
  68. package/lib/components/editor/command-center/FileSearchCommand.d.ts.map +1 -0
  69. package/lib/components/editor/command-center/FileSearchCommand.js +60 -0
  70. package/lib/components/editor/command-center/FileSearchCommand.js.map +1 -0
  71. package/lib/components/editor/command-center/TextSearchCommand.d.ts +20 -0
  72. package/lib/components/editor/command-center/TextSearchCommand.d.ts.map +1 -0
  73. package/lib/components/editor/command-center/TextSearchCommand.js +50 -0
  74. package/lib/components/editor/command-center/TextSearchCommand.js.map +1 -0
  75. package/lib/components/editor/edit-panel/DiagramEditor.d.ts +23 -0
  76. package/lib/components/editor/edit-panel/DiagramEditor.d.ts.map +1 -0
  77. package/lib/components/editor/edit-panel/DiagramEditor.js +71 -0
  78. package/lib/components/editor/edit-panel/DiagramEditor.js.map +1 -0
  79. package/lib/components/editor/edit-panel/EditPanel.d.ts +21 -0
  80. package/lib/components/editor/edit-panel/EditPanel.d.ts.map +1 -0
  81. package/lib/components/editor/edit-panel/EditPanel.js +55 -0
  82. package/lib/components/editor/edit-panel/EditPanel.js.map +1 -0
  83. package/lib/components/editor/edit-panel/FileEditor.d.ts +23 -0
  84. package/lib/components/editor/edit-panel/FileEditor.d.ts.map +1 -0
  85. package/lib/components/editor/edit-panel/FileEditor.js +114 -0
  86. package/lib/components/editor/edit-panel/FileEditor.js.map +1 -0
  87. package/lib/components/editor/shared/ConceptIconUtils.d.ts +17 -0
  88. package/lib/components/editor/shared/ConceptIconUtils.d.ts.map +1 -0
  89. package/lib/components/editor/shared/ConceptIconUtils.js +50 -0
  90. package/lib/components/editor/shared/ConceptIconUtils.js.map +1 -0
  91. package/lib/components/editor/side-bar/ConceptTreeExplorer.d.ts +24 -0
  92. package/lib/components/editor/side-bar/ConceptTreeExplorer.d.ts.map +1 -0
  93. package/lib/components/editor/side-bar/ConceptTreeExplorer.js +165 -0
  94. package/lib/components/editor/side-bar/ConceptTreeExplorer.js.map +1 -0
  95. package/lib/components/editor/side-bar/DirectoryTreeExplorer.d.ts +20 -0
  96. package/lib/components/editor/side-bar/DirectoryTreeExplorer.d.ts.map +1 -0
  97. package/lib/components/editor/side-bar/DirectoryTreeExplorer.js +142 -0
  98. package/lib/components/editor/side-bar/DirectoryTreeExplorer.js.map +1 -0
  99. package/lib/components/editor/side-bar/SideBar.d.ts +23 -0
  100. package/lib/components/editor/side-bar/SideBar.d.ts.map +1 -0
  101. package/lib/components/editor/side-bar/SideBar.js +40 -0
  102. package/lib/components/editor/side-bar/SideBar.js.map +1 -0
  103. package/lib/extensions.css +17 -0
  104. package/lib/extensions.css.map +1 -0
  105. package/lib/index.css +17 -0
  106. package/lib/index.css.map +1 -0
  107. package/lib/index.d.ts +22 -0
  108. package/lib/index.d.ts.map +1 -0
  109. package/lib/index.js +39 -0
  110. package/lib/index.js.map +1 -0
  111. package/lib/package.json +85 -0
  112. package/lib/server/PureServerClient.d.ts +55 -0
  113. package/lib/server/PureServerClient.d.ts.map +1 -0
  114. package/lib/server/PureServerClient.js +120 -0
  115. package/lib/server/PureServerClient.js.map +1 -0
  116. package/lib/server/models/Command.d.ts +24 -0
  117. package/lib/server/models/Command.d.ts.map +1 -0
  118. package/lib/server/models/Command.js +35 -0
  119. package/lib/server/models/Command.js.map +1 -0
  120. package/lib/server/models/ConceptTree.d.ts +76 -0
  121. package/lib/server/models/ConceptTree.d.ts.map +1 -0
  122. package/lib/server/models/ConceptTree.js +116 -0
  123. package/lib/server/models/ConceptTree.js.map +1 -0
  124. package/lib/server/models/DiagramInfo.d.ts +144 -0
  125. package/lib/server/models/DiagramInfo.d.ts.map +1 -0
  126. package/lib/server/models/DiagramInfo.js +478 -0
  127. package/lib/server/models/DiagramInfo.js.map +1 -0
  128. package/lib/server/models/DirectoryTree.d.ts +37 -0
  129. package/lib/server/models/DirectoryTree.d.ts.map +1 -0
  130. package/lib/server/models/DirectoryTree.js +70 -0
  131. package/lib/server/models/DirectoryTree.js.map +1 -0
  132. package/lib/server/models/Execution.d.ts +100 -0
  133. package/lib/server/models/Execution.d.ts.map +1 -0
  134. package/lib/server/models/Execution.js +183 -0
  135. package/lib/server/models/Execution.js.map +1 -0
  136. package/lib/server/models/Initialization.d.ts +49 -0
  137. package/lib/server/models/Initialization.d.ts.map +1 -0
  138. package/lib/server/models/Initialization.js +64 -0
  139. package/lib/server/models/Initialization.js.map +1 -0
  140. package/lib/server/models/PureFile.d.ts +34 -0
  141. package/lib/server/models/PureFile.d.ts.map +1 -0
  142. package/lib/server/models/PureFile.js +56 -0
  143. package/lib/server/models/PureFile.js.map +1 -0
  144. package/lib/server/models/SearchEntry.d.ts +36 -0
  145. package/lib/server/models/SearchEntry.d.ts.map +1 -0
  146. package/lib/server/models/SearchEntry.js +63 -0
  147. package/lib/server/models/SearchEntry.js.map +1 -0
  148. package/lib/server/models/SourceInformation.d.ts +25 -0
  149. package/lib/server/models/SourceInformation.d.ts.map +1 -0
  150. package/lib/server/models/SourceInformation.js +35 -0
  151. package/lib/server/models/SourceInformation.js.map +1 -0
  152. package/lib/server/models/Test.d.ts +57 -0
  153. package/lib/server/models/Test.d.ts.map +1 -0
  154. package/lib/server/models/Test.js +92 -0
  155. package/lib/server/models/Test.js.map +1 -0
  156. package/lib/server/models/Usage.d.ts +31 -0
  157. package/lib/server/models/Usage.d.ts.map +1 -0
  158. package/lib/server/models/Usage.js +36 -0
  159. package/lib/server/models/Usage.js.map +1 -0
  160. package/lib/stores/ConceptTreeState.d.ts +34 -0
  161. package/lib/stores/ConceptTreeState.d.ts.map +1 -0
  162. package/lib/stores/ConceptTreeState.js +117 -0
  163. package/lib/stores/ConceptTreeState.js.map +1 -0
  164. package/lib/stores/DiagramEditorState.d.ts +40 -0
  165. package/lib/stores/DiagramEditorState.d.ts.map +1 -0
  166. package/lib/stores/DiagramEditorState.js +90 -0
  167. package/lib/stores/DiagramEditorState.js.map +1 -0
  168. package/lib/stores/DirectoryTreeState.d.ts +35 -0
  169. package/lib/stores/DirectoryTreeState.d.ts.map +1 -0
  170. package/lib/stores/DirectoryTreeState.js +119 -0
  171. package/lib/stores/DirectoryTreeState.js.map +1 -0
  172. package/lib/stores/EditorConfig.d.ts +25 -0
  173. package/lib/stores/EditorConfig.d.ts.map +1 -0
  174. package/lib/stores/EditorConfig.js +27 -0
  175. package/lib/stores/EditorConfig.js.map +1 -0
  176. package/lib/stores/EditorStore.d.ts +102 -0
  177. package/lib/stores/EditorStore.d.ts.map +1 -0
  178. package/lib/stores/EditorStore.js +761 -0
  179. package/lib/stores/EditorStore.js.map +1 -0
  180. package/lib/stores/EditorTabManagerState.d.ts +31 -0
  181. package/lib/stores/EditorTabManagerState.d.ts.map +1 -0
  182. package/lib/stores/EditorTabManagerState.js +62 -0
  183. package/lib/stores/EditorTabManagerState.js.map +1 -0
  184. package/lib/stores/FileEditorState.d.ts +37 -0
  185. package/lib/stores/FileEditorState.d.ts.map +1 -0
  186. package/lib/stores/FileEditorState.js +99 -0
  187. package/lib/stores/FileEditorState.js.map +1 -0
  188. package/lib/stores/LegendPureIDEApplicationPlugin.d.ts +26 -0
  189. package/lib/stores/LegendPureIDEApplicationPlugin.d.ts.map +1 -0
  190. package/lib/stores/LegendPureIDEApplicationPlugin.js +27 -0
  191. package/lib/stores/LegendPureIDEApplicationPlugin.js.map +1 -0
  192. package/lib/stores/LegendPureIDEBaseStore.d.ts +25 -0
  193. package/lib/stores/LegendPureIDEBaseStore.d.ts.map +1 -0
  194. package/lib/stores/LegendPureIDEBaseStore.js +25 -0
  195. package/lib/stores/LegendPureIDEBaseStore.js.map +1 -0
  196. package/lib/stores/LegendPureIDECommand.d.ts +32 -0
  197. package/lib/stores/LegendPureIDECommand.d.ts.map +1 -0
  198. package/lib/stores/LegendPureIDECommand.js +82 -0
  199. package/lib/stores/LegendPureIDECommand.js.map +1 -0
  200. package/lib/stores/SearchCommandState.d.ts +28 -0
  201. package/lib/stores/SearchCommandState.d.ts.map +1 -0
  202. package/lib/stores/SearchCommandState.js +53 -0
  203. package/lib/stores/SearchCommandState.js.map +1 -0
  204. package/lib/stores/SearchResultState.d.ts +43 -0
  205. package/lib/stores/SearchResultState.d.ts.map +1 -0
  206. package/lib/stores/SearchResultState.js +92 -0
  207. package/lib/stores/SearchResultState.js.map +1 -0
  208. package/lib/stores/TestRunnerState.d.ts +87 -0
  209. package/lib/stores/TestRunnerState.d.ts.map +1 -0
  210. package/lib/stores/TestRunnerState.js +336 -0
  211. package/lib/stores/TestRunnerState.js.map +1 -0
  212. package/lib/stores/TreeState.d.ts +42 -0
  213. package/lib/stores/TreeState.d.ts.map +1 -0
  214. package/lib/stores/TreeState.js +139 -0
  215. package/lib/stores/TreeState.js.map +1 -0
  216. package/package.json +85 -0
  217. package/src/application/LegendPureIDE.tsx +73 -0
  218. package/src/application/LegendPureIDEApplicationConfig.ts +58 -0
  219. package/src/application/LegendPureIDEPluginManager.ts +67 -0
  220. package/src/components/Core_LegendPureIDEApplicationPlugin.tsx +37 -0
  221. package/src/components/LegendPureIDEApplication.tsx +27 -0
  222. package/src/components/LegendPureIDEBaseStoreProvider.tsx +57 -0
  223. package/src/components/editor/ActivityBar.tsx +74 -0
  224. package/src/components/editor/Editor.tsx +180 -0
  225. package/src/components/editor/EditorStoreProvider.tsx +57 -0
  226. package/src/components/editor/StatusBar.tsx +95 -0
  227. package/src/components/editor/aux-panel/AuxiliaryPanel.tsx +155 -0
  228. package/src/components/editor/aux-panel/ConsolePanel.tsx +49 -0
  229. package/src/components/editor/aux-panel/SearchPanel.tsx +421 -0
  230. package/src/components/editor/aux-panel/TestRunnerPanel.tsx +455 -0
  231. package/src/components/editor/command-center/CreateNewDirectoryCommand.tsx +86 -0
  232. package/src/components/editor/command-center/CreateNewFileCommand.tsx +84 -0
  233. package/src/components/editor/command-center/FileSearchCommand.tsx +112 -0
  234. package/src/components/editor/command-center/TextSearchCommand.tsx +103 -0
  235. package/src/components/editor/edit-panel/DiagramEditor.tsx +108 -0
  236. package/src/components/editor/edit-panel/EditPanel.tsx +114 -0
  237. package/src/components/editor/edit-panel/FileEditor.tsx +156 -0
  238. package/src/components/editor/shared/ConceptIconUtils.tsx +78 -0
  239. package/src/components/editor/side-bar/ConceptTreeExplorer.tsx +401 -0
  240. package/src/components/editor/side-bar/DirectoryTreeExplorer.tsx +366 -0
  241. package/src/components/editor/side-bar/SideBar.tsx +51 -0
  242. package/src/index.tsx +46 -0
  243. package/src/server/PureServerClient.ts +299 -0
  244. package/src/server/models/Command.ts +40 -0
  245. package/src/server/models/ConceptTree.ts +152 -0
  246. package/src/server/models/DiagramInfo.ts +793 -0
  247. package/src/server/models/DirectoryTree.ts +100 -0
  248. package/src/server/models/Execution.ts +223 -0
  249. package/src/server/models/Initialization.ts +92 -0
  250. package/src/server/models/PureFile.ts +76 -0
  251. package/src/server/models/SearchEntry.ts +85 -0
  252. package/src/server/models/SourceInformation.ts +37 -0
  253. package/src/server/models/Test.ts +125 -0
  254. package/src/server/models/Usage.ts +49 -0
  255. package/src/stores/ConceptTreeState.ts +156 -0
  256. package/src/stores/DiagramEditorState.ts +150 -0
  257. package/src/stores/DirectoryTreeState.ts +168 -0
  258. package/src/stores/EditorConfig.ts +26 -0
  259. package/src/stores/EditorStore.ts +1087 -0
  260. package/src/stores/EditorTabManagerState.ts +74 -0
  261. package/src/stores/FileEditorState.ts +148 -0
  262. package/src/stores/LegendPureIDEApplicationPlugin.ts +30 -0
  263. package/src/stores/LegendPureIDEBaseStore.ts +36 -0
  264. package/src/stores/LegendPureIDECommand.ts +84 -0
  265. package/src/stores/SearchCommandState.ts +61 -0
  266. package/src/stores/SearchResultState.ts +131 -0
  267. package/src/stores/TestRunnerState.ts +470 -0
  268. package/src/stores/TreeState.ts +179 -0
  269. package/tsconfig.json +98 -0
@@ -0,0 +1,1087 @@
1
+ /**
2
+ * Copyright (c) 2020-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { action, flow, flowResult, makeObservable, observable } from 'mobx';
18
+ import { ACTIVITY_MODE, AUX_PANEL_MODE } from './EditorConfig.js';
19
+ import { FileEditorState } from './FileEditorState.js';
20
+ import { deserialize } from 'serializr';
21
+ import {
22
+ FileCoordinate,
23
+ PureFile,
24
+ trimPathLeadingSlash,
25
+ } from '../server/models/PureFile.js';
26
+ import { DirectoryTreeState } from './DirectoryTreeState.js';
27
+ import { ConceptTreeState } from './ConceptTreeState.js';
28
+ import {
29
+ type InitializationActivity,
30
+ type InitializationResult,
31
+ InitializationFailureWithSourceResult,
32
+ InitializationFailureResult,
33
+ deserializeInitializationnResult,
34
+ } from '../server/models/Initialization.js';
35
+ import {
36
+ type CandidateWithPackageNotImported,
37
+ type ExecutionActivity,
38
+ type ExecutionResult,
39
+ TestExecutionResult,
40
+ UnmatchedFunctionResult,
41
+ UnmatchedResult,
42
+ GetConceptResult,
43
+ deserializeExecutionResult,
44
+ ExecutionFailureResult,
45
+ ExecutionSuccessResult,
46
+ } from '../server/models/Execution.js';
47
+ import {
48
+ type SearchResultEntry,
49
+ getSearchResultEntry,
50
+ } from '../server/models/SearchEntry.js';
51
+ import {
52
+ type SearchState,
53
+ UsageResultState,
54
+ UnmatchedFunctionExecutionResultState,
55
+ UnmatchExecutionResultState,
56
+ SearchResultState,
57
+ } from './SearchResultState.js';
58
+ import { TestRunnerState } from './TestRunnerState.js';
59
+ import {
60
+ type UsageConcept,
61
+ getUsageConceptLabel,
62
+ Usage,
63
+ } from '../server/models/Usage.js';
64
+ import {
65
+ type CommandResult,
66
+ CommandFailureResult,
67
+ deserializeCommandResult,
68
+ } from '../server/models/Command.js';
69
+ import {
70
+ ActionAlertActionType,
71
+ ActionAlertType,
72
+ type CommandRegistrar,
73
+ } from '@finos/legend-application';
74
+ import {
75
+ type GeneratorFn,
76
+ type PlainObject,
77
+ isNonNullable,
78
+ NetworkClient,
79
+ ActionState,
80
+ assertErrorThrown,
81
+ guaranteeNonNullable,
82
+ } from '@finos/legend-shared';
83
+ import { PureClient as PureServerClient } from '../server/PureServerClient.js';
84
+ import { PanelDisplayState } from '@finos/legend-art';
85
+ import { DiagramEditorState } from './DiagramEditorState.js';
86
+ import { DiagramInfo, serializeDiagram } from '../server/models/DiagramInfo.js';
87
+ import type { LegendPureIDEApplicationStore } from './LegendPureIDEBaseStore.js';
88
+ import { SearchCommandState } from './SearchCommandState.js';
89
+ import { EditorTabManagerState } from './EditorTabManagerState.js';
90
+ import { LEGEND_PURE_IDE_COMMAND_KEY } from './LegendPureIDECommand.js';
91
+
92
+ export class EditorStore implements CommandRegistrar {
93
+ readonly applicationStore: LegendPureIDEApplicationStore;
94
+
95
+ readonly initState = ActionState.create();
96
+ readonly directoryTreeState: DirectoryTreeState;
97
+ readonly conceptTreeState: ConceptTreeState;
98
+ readonly client: PureServerClient;
99
+
100
+ // Layout
101
+ isMaxAuxPanelSizeSet = false;
102
+ activeAuxPanelMode = AUX_PANEL_MODE.CONSOLE;
103
+ readonly auxPanelDisplayState = new PanelDisplayState({
104
+ initial: 0,
105
+ default: 300,
106
+ snap: 100,
107
+ });
108
+ activeActivity?: ACTIVITY_MODE = ACTIVITY_MODE.CONCEPT;
109
+ readonly sideBarDisplayState = new PanelDisplayState({
110
+ initial: 300,
111
+ default: 300,
112
+ snap: 150,
113
+ });
114
+ readonly tabManagerState = new EditorTabManagerState(this);
115
+
116
+ readonly executionState = ActionState.create();
117
+ navigationStack: FileCoordinate[] = []; // TODO?: we might want to limit the number of items in this stack
118
+
119
+ // Console
120
+ consoleText?: string | undefined;
121
+
122
+ // Search Command
123
+ readonly fileSearchCommandLoadingState = ActionState.create();
124
+ readonly fileSearchCommandState = new SearchCommandState();
125
+ openFileSearchCommand = false;
126
+ fileSearchCommandResults: string[] = [];
127
+ readonly textSearchCommandLoadingState = ActionState.create();
128
+ readonly textSearchCommandState = new SearchCommandState();
129
+ openTextSearchCommand = false;
130
+
131
+ // Search Panel
132
+ searchState?: SearchState | undefined;
133
+
134
+ // Test
135
+ readonly testRunState = ActionState.create();
136
+ testRunnerState?: TestRunnerState | undefined;
137
+
138
+ constructor(applicationStore: LegendPureIDEApplicationStore) {
139
+ makeObservable(this, {
140
+ isMaxAuxPanelSizeSet: observable,
141
+ activeAuxPanelMode: observable,
142
+ activeActivity: observable,
143
+ consoleText: observable,
144
+ navigationStack: observable,
145
+ openFileSearchCommand: observable,
146
+ fileSearchCommandResults: observable,
147
+ fileSearchCommandState: observable,
148
+ openTextSearchCommand: observable,
149
+ textSearchCommandState: observable,
150
+ searchState: observable,
151
+ testRunnerState: observable,
152
+
153
+ setOpenFileSearchCommand: action,
154
+ setOpenTextSearchCommand: action,
155
+ setActiveAuxPanelMode: action,
156
+ setActiveActivity: action,
157
+ setConsoleText: action,
158
+ setSearchState: action,
159
+ setTestRunnerState: action,
160
+ pullInitializationActivity: action,
161
+ pullExecutionStatus: action,
162
+
163
+ initialize: flow,
164
+ checkIfSessionWakingUp: flow,
165
+ loadDiagram: flow,
166
+ loadFile: flow,
167
+ reloadFile: flow,
168
+ execute: flow,
169
+ executeGo: flow,
170
+ manageExecuteGoResult: flow,
171
+ executeTests: flow,
172
+ executeFullTestSuite: flow,
173
+ executeNavigation: flow,
174
+ navigateBack: flow,
175
+ executeSaveAndReset: flow,
176
+ fullReCompile: flow,
177
+ refreshTrees: flow,
178
+ updateFileUsingSuggestionCandidate: flow,
179
+ updateFile: flow,
180
+ searchFile: flow,
181
+ searchText: flow,
182
+ findUsages: flow,
183
+ command: flow,
184
+ createNewDirectory: flow,
185
+ createNewFile: flow,
186
+ deleteDirectoryOrFile: flow,
187
+ });
188
+
189
+ this.applicationStore = applicationStore;
190
+ this.directoryTreeState = new DirectoryTreeState(this);
191
+ this.conceptTreeState = new ConceptTreeState(this);
192
+ this.client = new PureServerClient(
193
+ new NetworkClient({
194
+ baseUrl: this.applicationStore.config.useDynamicPureServer
195
+ ? window.location.origin
196
+ : this.applicationStore.config.pureUrl,
197
+ }),
198
+ );
199
+ }
200
+
201
+ setOpenFileSearchCommand(val: boolean): void {
202
+ this.openFileSearchCommand = val;
203
+ }
204
+
205
+ setOpenTextSearchCommand(val: boolean): void {
206
+ this.openTextSearchCommand = val;
207
+ }
208
+
209
+ setActiveAuxPanelMode(val: AUX_PANEL_MODE): void {
210
+ this.activeAuxPanelMode = val;
211
+ }
212
+
213
+ setConsoleText(value: string | undefined): void {
214
+ this.consoleText = value;
215
+ }
216
+
217
+ setSearchState(val: SearchState | undefined): void {
218
+ this.searchState = val;
219
+ }
220
+
221
+ setTestRunnerState(val: TestRunnerState | undefined): void {
222
+ this.testRunnerState = val;
223
+ }
224
+
225
+ cleanUp(): void {
226
+ // dismiss all the alerts as these are parts of application, if we don't do this, we might
227
+ // end up blocking other parts of the app
228
+ // e.g. trying going to an unknown workspace, we will be redirected to the home page
229
+ // but the blocking alert for not-found workspace will still block the app
230
+ this.applicationStore.setBlockingAlert(undefined);
231
+ this.applicationStore.setActionAlertInfo(undefined);
232
+ }
233
+
234
+ /**
235
+ * This is the entry of the app logic where initialization of editor states happens
236
+ * Here, we ensure the order of calls after checking existence of current project and workspace
237
+ * If either of them does not exist, we cannot proceed.
238
+ */
239
+ *initialize(
240
+ fullInit: boolean,
241
+ func: (() => Promise<void>) | undefined,
242
+ mode: string | undefined,
243
+ fastCompile: string | undefined,
244
+ ): GeneratorFn<void> {
245
+ if (!this.initState.isInInitialState) {
246
+ this.applicationStore.notifyIllegalState(
247
+ 'Editor store is re-initialized',
248
+ );
249
+ return;
250
+ }
251
+ // set PURE IDE mode
252
+ this.client.mode = mode;
253
+ this.client.compilerMode = fastCompile;
254
+ // initialize editor
255
+ this.initState.inProgress();
256
+ try {
257
+ const initializationPromise = this.client.initialize(!fullInit);
258
+ this.applicationStore.setBlockingAlert({
259
+ message: 'Loading Pure IDE...',
260
+ prompt:
261
+ 'Please be patient as we are building the initial application state',
262
+ showLoading: true,
263
+ });
264
+ yield this.pullInitializationActivity();
265
+ this.applicationStore.setBlockingAlert(undefined);
266
+ const openWelcomeFilePromise = flowResult(this.loadFile('/welcome.pure'));
267
+ const directoryTreeInitPromise = this.directoryTreeState.initialize();
268
+ const conceptTreeInitPromise = this.conceptTreeState.initialize();
269
+ const result = deserializeInitializationnResult(
270
+ (yield initializationPromise) as PlainObject<InitializationResult>,
271
+ );
272
+ if (result.text) {
273
+ this.setConsoleText(result.text);
274
+ this.setActiveAuxPanelMode(AUX_PANEL_MODE.CONSOLE);
275
+ this.auxPanelDisplayState.open();
276
+ }
277
+ if (result instanceof InitializationFailureResult) {
278
+ if (result.sessionError) {
279
+ this.applicationStore.setBlockingAlert({
280
+ message: 'Session corrupted',
281
+ prompt: result.sessionError,
282
+ });
283
+ } else if (result instanceof InitializationFailureWithSourceResult) {
284
+ yield flowResult(
285
+ this.loadFile(
286
+ result.source,
287
+ new FileCoordinate(
288
+ result.source,
289
+ result.line,
290
+ result.column,
291
+ (result.text ?? '').split('\n').filter(Boolean)[0],
292
+ ),
293
+ ),
294
+ );
295
+ }
296
+ } else {
297
+ if (func) {
298
+ yield func();
299
+ }
300
+ yield Promise.all([
301
+ openWelcomeFilePromise,
302
+ directoryTreeInitPromise,
303
+ conceptTreeInitPromise,
304
+ ]);
305
+ }
306
+ } catch (error) {
307
+ assertErrorThrown(error);
308
+ this.applicationStore.notifyError(error);
309
+ this.initState.fail();
310
+ this.applicationStore.setBlockingAlert({
311
+ message: 'Failed to initialize IDE',
312
+ prompt:
313
+ 'Make sure the IDE server is working, otherwise try to restart it',
314
+ });
315
+ return;
316
+ }
317
+ this.initState.pass();
318
+ }
319
+
320
+ *checkIfSessionWakingUp(message?: string): GeneratorFn<void> {
321
+ this.applicationStore.setBlockingAlert({
322
+ message: message ?? 'Checking IDE session...',
323
+ showLoading: true,
324
+ });
325
+ yield this.pullInitializationActivity(
326
+ (activity: InitializationActivity) => {
327
+ if (activity.text) {
328
+ this.applicationStore.setBlockingAlert({
329
+ message: message ?? 'Checking IDE session...',
330
+ prompt: activity.text,
331
+ showLoading: true,
332
+ });
333
+ }
334
+ },
335
+ );
336
+ this.applicationStore.setBlockingAlert(undefined);
337
+ }
338
+
339
+ async pullInitializationActivity(
340
+ fn?: (activity: InitializationActivity) => void,
341
+ ): Promise<void> {
342
+ const result =
343
+ (await this.client.getInitializationActivity()) as unknown as InitializationActivity;
344
+ if (result.initializing) {
345
+ return new Promise((resolve, reject) =>
346
+ setTimeout(() => {
347
+ try {
348
+ resolve(this.pullInitializationActivity());
349
+ } catch (error) {
350
+ reject(error);
351
+ }
352
+ }, 1000),
353
+ );
354
+ }
355
+ return Promise.resolve();
356
+ }
357
+
358
+ registerCommands(): void {
359
+ this.applicationStore.commandCenter.registerCommand({
360
+ key: LEGEND_PURE_IDE_COMMAND_KEY.SEARCH_FILE,
361
+ trigger: () => this.initState.hasSucceeded,
362
+ action: () => this.setOpenFileSearchCommand(true),
363
+ });
364
+ this.applicationStore.commandCenter.registerCommand({
365
+ key: LEGEND_PURE_IDE_COMMAND_KEY.SEARCH_TEXT,
366
+ trigger: () => this.initState.hasSucceeded,
367
+ action: () => this.setOpenTextSearchCommand(true),
368
+ });
369
+ this.applicationStore.commandCenter.registerCommand({
370
+ key: LEGEND_PURE_IDE_COMMAND_KEY.GO_TO_FILE,
371
+ action: () => {
372
+ if (this.tabManagerState.currentTab instanceof FileEditorState) {
373
+ this.directoryTreeState.revealPath(
374
+ this.tabManagerState.currentTab.filePath,
375
+ true,
376
+ );
377
+ }
378
+ },
379
+ });
380
+ this.applicationStore.commandCenter.registerCommand({
381
+ key: LEGEND_PURE_IDE_COMMAND_KEY.TOGGLE_AUX_PANEL,
382
+ trigger: () => this.initState.hasSucceeded,
383
+ action: () => this.auxPanelDisplayState.toggle(),
384
+ });
385
+ this.applicationStore.commandCenter.registerCommand({
386
+ key: LEGEND_PURE_IDE_COMMAND_KEY.EXECUTE,
387
+ action: () => {
388
+ flowResult(this.executeGo()).catch(
389
+ this.applicationStore.alertUnhandledError,
390
+ );
391
+ },
392
+ });
393
+ this.applicationStore.commandCenter.registerCommand({
394
+ key: LEGEND_PURE_IDE_COMMAND_KEY.FULL_RECOMPILE,
395
+ action: () => {
396
+ flowResult(this.fullReCompile(false)).catch(
397
+ this.applicationStore.alertUnhandledError,
398
+ );
399
+ },
400
+ });
401
+ this.applicationStore.commandCenter.registerCommand({
402
+ key: LEGEND_PURE_IDE_COMMAND_KEY.FULL_RECOMPILE_WITH_FULL_INIT,
403
+ action: () => {
404
+ flowResult(this.fullReCompile(true)).catch(
405
+ this.applicationStore.alertUnhandledError,
406
+ );
407
+ },
408
+ });
409
+ this.applicationStore.commandCenter.registerCommand({
410
+ key: LEGEND_PURE_IDE_COMMAND_KEY.RUN_ALL_TESTS,
411
+ action: () => {
412
+ flowResult(this.executeFullTestSuite(false)).catch(
413
+ this.applicationStore.alertUnhandledError,
414
+ );
415
+ },
416
+ });
417
+ this.applicationStore.commandCenter.registerCommand({
418
+ key: LEGEND_PURE_IDE_COMMAND_KEY.RUN_RELAVANT_TESTS,
419
+ action: () => {
420
+ flowResult(this.executeFullTestSuite(true)).catch(
421
+ this.applicationStore.alertUnhandledError,
422
+ );
423
+ },
424
+ });
425
+ }
426
+
427
+ deregisterCommands(): void {
428
+ [
429
+ LEGEND_PURE_IDE_COMMAND_KEY.SEARCH_FILE,
430
+ LEGEND_PURE_IDE_COMMAND_KEY.SEARCH_TEXT,
431
+ LEGEND_PURE_IDE_COMMAND_KEY.GO_TO_FILE,
432
+ LEGEND_PURE_IDE_COMMAND_KEY.TOGGLE_AUX_PANEL,
433
+ LEGEND_PURE_IDE_COMMAND_KEY.EXECUTE,
434
+ LEGEND_PURE_IDE_COMMAND_KEY.FULL_RECOMPILE,
435
+ LEGEND_PURE_IDE_COMMAND_KEY.FULL_RECOMPILE_WITH_FULL_INIT,
436
+ LEGEND_PURE_IDE_COMMAND_KEY.RUN_ALL_TESTS,
437
+ LEGEND_PURE_IDE_COMMAND_KEY.RUN_RELAVANT_TESTS,
438
+ ].forEach((key) =>
439
+ this.applicationStore.commandCenter.deregisterCommand(key),
440
+ );
441
+ }
442
+
443
+ setActiveActivity(
444
+ activity: ACTIVITY_MODE,
445
+ options?: { keepShowingIfMatchedCurrent?: boolean },
446
+ ): void {
447
+ if (!this.sideBarDisplayState.isOpen) {
448
+ this.sideBarDisplayState.open();
449
+ } else if (
450
+ activity === this.activeActivity &&
451
+ !options?.keepShowingIfMatchedCurrent
452
+ ) {
453
+ this.sideBarDisplayState.close();
454
+ }
455
+ this.activeActivity = activity;
456
+ }
457
+
458
+ *loadDiagram(filePath: string, diagramPath: string): GeneratorFn<void> {
459
+ const existingDiagramEditorState = this.tabManagerState.tabs.find(
460
+ (tab): tab is DiagramEditorState =>
461
+ tab instanceof DiagramEditorState && tab.filePath === filePath,
462
+ );
463
+ if (existingDiagramEditorState) {
464
+ this.tabManagerState.openTab(existingDiagramEditorState);
465
+ } else {
466
+ yield flowResult(this.checkIfSessionWakingUp());
467
+ const newDiagramEditorState = new DiagramEditorState(
468
+ this,
469
+ deserialize(DiagramInfo, yield this.client.getDiagramInfo(diagramPath)),
470
+ diagramPath,
471
+ filePath,
472
+ );
473
+ this.tabManagerState.openTab(newDiagramEditorState);
474
+ }
475
+ }
476
+
477
+ *loadFile(path: string, coordinate?: FileCoordinate): GeneratorFn<void> {
478
+ const existingFileEditorState = this.tabManagerState.tabs.find(
479
+ (tab): tab is FileEditorState =>
480
+ tab instanceof FileEditorState && tab.filePath === path,
481
+ );
482
+ if (existingFileEditorState) {
483
+ if (coordinate) {
484
+ existingFileEditorState.setCoordinate(coordinate);
485
+ }
486
+ this.tabManagerState.openTab(existingFileEditorState);
487
+ } else {
488
+ yield flowResult(this.checkIfSessionWakingUp());
489
+ const newFileEditorState = new FileEditorState(
490
+ this,
491
+ deserialize(PureFile, yield this.client.getFile(path)),
492
+ path,
493
+ coordinate,
494
+ );
495
+ this.tabManagerState.openTab(newFileEditorState);
496
+ }
497
+ }
498
+
499
+ *reloadFile(filePath: string): GeneratorFn<void> {
500
+ yield Promise.all(
501
+ this.tabManagerState.tabs.map(async (tab) => {
502
+ if (tab instanceof FileEditorState && tab.filePath === filePath) {
503
+ tab.setFile(
504
+ deserialize(PureFile, await this.client.getFile(filePath)),
505
+ );
506
+ tab.setCoordinate(undefined);
507
+ } else if (
508
+ tab instanceof DiagramEditorState &&
509
+ tab.filePath === filePath
510
+ ) {
511
+ tab.rebuild(
512
+ deserialize(
513
+ DiagramInfo,
514
+ await this.client.getDiagramInfo(tab.diagramPath),
515
+ ),
516
+ );
517
+ }
518
+ }),
519
+ );
520
+ }
521
+
522
+ *execute(
523
+ url: string,
524
+ extraParams: Record<PropertyKey, unknown>,
525
+ checkExecutionStatus: boolean,
526
+ manageResult: (result: ExecutionResult) => Promise<void>,
527
+ ): GeneratorFn<void> {
528
+ if (!this.initState.hasSucceeded) {
529
+ this.applicationStore.notifyWarning(
530
+ `Can't execute while initializing application`,
531
+ );
532
+ return;
533
+ }
534
+ if (this.executionState.isInProgress) {
535
+ this.applicationStore.notifyWarning(
536
+ 'Another execution is already in progress!',
537
+ );
538
+ return;
539
+ }
540
+ // reset search state before execution
541
+ if (!(this.searchState instanceof SearchResultState)) {
542
+ this.setSearchState(undefined);
543
+ }
544
+ this.executionState.inProgress();
545
+ try {
546
+ const openedFiles = this.tabManagerState.tabs
547
+ .map((tab) => {
548
+ if (tab instanceof FileEditorState) {
549
+ return {
550
+ path: tab.filePath,
551
+ code: tab.file.content,
552
+ };
553
+ } else if (tab instanceof DiagramEditorState) {
554
+ return {
555
+ diagram: tab.diagramPath,
556
+ code: serializeDiagram(tab.diagram),
557
+ };
558
+ }
559
+ return undefined;
560
+ })
561
+ .filter(isNonNullable);
562
+ const executionPromise = this.client.execute(
563
+ openedFiles,
564
+ url,
565
+ extraParams,
566
+ );
567
+ // NOTE: when we execute, it could take a while, and by default, we run a status check which potentially
568
+ // blocks the screen, as such, to be less disruptive to the UX and to avoid creating the illusion of slowness
569
+ // we will have a wait time, if execution is below this threshold, we will not conduct the check.
570
+ // The current threshold we choose is 1000ms, i.e. the execution should be sub-second
571
+ const WAIT_TIME_TO_TRIGGER_STATUS_CHECK = 1000;
572
+ let executionPromiseFinished = false;
573
+ let executionPromiseResult: PlainObject<ExecutionResult> | undefined;
574
+ yield Promise.all<void>([
575
+ executionPromise.then((value) => {
576
+ executionPromiseFinished = true;
577
+ executionPromiseResult = value;
578
+ }),
579
+ new Promise((resolve) =>
580
+ setTimeout(
581
+ () => {
582
+ if (!executionPromiseFinished && checkExecutionStatus) {
583
+ this.applicationStore.setBlockingAlert({
584
+ message: 'Executing...',
585
+ prompt: 'Please do not refresh the application',
586
+ showLoading: true,
587
+ });
588
+ resolve(this.pullExecutionStatus());
589
+ }
590
+ resolve();
591
+ },
592
+ WAIT_TIME_TO_TRIGGER_STATUS_CHECK,
593
+ true,
594
+ ),
595
+ ),
596
+ ]);
597
+ const result = deserializeExecutionResult(
598
+ guaranteeNonNullable(executionPromiseResult),
599
+ );
600
+ this.applicationStore.setBlockingAlert(undefined);
601
+ this.setConsoleText(result.text);
602
+ if (result instanceof ExecutionFailureResult) {
603
+ this.applicationStore.notifyWarning('Execution failed!');
604
+ if (result.sessionError) {
605
+ this.applicationStore.setBlockingAlert({
606
+ message: 'Session corrupted',
607
+ prompt: result.sessionError,
608
+ });
609
+ } else {
610
+ yield flowResult(manageResult(result));
611
+ }
612
+ } else if (result instanceof ExecutionSuccessResult) {
613
+ this.applicationStore.notifySuccess('Execution succeeded!');
614
+ if (result.reinit) {
615
+ this.applicationStore.setBlockingAlert({
616
+ message: 'Reinitializing...',
617
+ prompt: 'Please do not refresh the application',
618
+ showLoading: true,
619
+ });
620
+ this.initState.reset();
621
+ yield flowResult(
622
+ this.initialize(
623
+ false,
624
+ () =>
625
+ flowResult(
626
+ this.execute(
627
+ url,
628
+ extraParams,
629
+ checkExecutionStatus,
630
+ manageResult,
631
+ ),
632
+ ),
633
+ this.client.mode,
634
+ this.client.compilerMode,
635
+ ),
636
+ );
637
+ } else {
638
+ yield flowResult(manageResult(result));
639
+ }
640
+ } else {
641
+ yield flowResult(manageResult(result));
642
+ }
643
+ } finally {
644
+ this.applicationStore.setBlockingAlert(undefined);
645
+ this.executionState.reset();
646
+ }
647
+ }
648
+
649
+ // NOTE: currently backend do not suppor this operation, so we temporarily disable it, but
650
+ // in theory, this will pull up a blocking modal to show the execution status to user
651
+ async pullExecutionStatus(): Promise<void> {
652
+ const result =
653
+ (await this.client.getExecutionActivity()) as unknown as ExecutionActivity;
654
+ this.applicationStore.setBlockingAlert({
655
+ message: 'Executing...',
656
+ prompt: result.text
657
+ ? result.text
658
+ : 'Please do not refresh the application',
659
+ showLoading: true,
660
+ });
661
+ if (result.executing) {
662
+ return new Promise((resolve, reject) =>
663
+ setTimeout(() => {
664
+ try {
665
+ resolve(this.pullExecutionStatus());
666
+ } catch (error) {
667
+ reject(error);
668
+ }
669
+ // NOTE: tune this slightly lower for better experience, also for sub-second execution, setting a high number
670
+ // might create the illusion that the system is slow
671
+ }, 500),
672
+ );
673
+ }
674
+ this.applicationStore.setBlockingAlert({
675
+ message: 'Executing...',
676
+ prompt: 'Please do not refresh the application',
677
+ showLoading: true,
678
+ });
679
+ return Promise.resolve();
680
+ }
681
+
682
+ *executeGo(): GeneratorFn<void> {
683
+ yield flowResult(
684
+ this.execute('executeGo', {}, true, (result: ExecutionResult) =>
685
+ flowResult(this.manageExecuteGoResult(result)),
686
+ ),
687
+ );
688
+ }
689
+
690
+ *manageExecuteGoResult(result: ExecutionResult): GeneratorFn<void> {
691
+ const refreshTreesPromise = flowResult(this.refreshTrees());
692
+ if (result instanceof ExecutionFailureResult) {
693
+ yield flowResult(
694
+ this.loadFile(
695
+ result.source,
696
+ new FileCoordinate(
697
+ result.source,
698
+ result.line,
699
+ result.column,
700
+ result.text.split('\n').filter(Boolean)[0],
701
+ ),
702
+ ),
703
+ );
704
+ if (result instanceof UnmatchedFunctionResult) {
705
+ this.setSearchState(
706
+ new UnmatchedFunctionExecutionResultState(this, result),
707
+ );
708
+ this.setActiveAuxPanelMode(AUX_PANEL_MODE.SEARCH_RESULT);
709
+ this.auxPanelDisplayState.open();
710
+ } else if (result instanceof UnmatchedResult) {
711
+ this.setSearchState(new UnmatchExecutionResultState(this, result));
712
+ this.setActiveAuxPanelMode(AUX_PANEL_MODE.SEARCH_RESULT);
713
+ this.auxPanelDisplayState.open();
714
+ }
715
+ } else if (result instanceof ExecutionSuccessResult) {
716
+ if (result.modifiedFiles.length) {
717
+ for (const path of result.modifiedFiles) {
718
+ yield flowResult(this.reloadFile(path));
719
+ }
720
+ }
721
+ }
722
+ yield refreshTreesPromise;
723
+ }
724
+
725
+ *executeTests(path: string, relevantTestsOnly?: boolean): GeneratorFn<void> {
726
+ if (this.testRunState.isInProgress) {
727
+ this.applicationStore.notifyWarning(
728
+ 'Test runner is working. Please try again later',
729
+ );
730
+ return;
731
+ }
732
+ this.testRunState.inProgress();
733
+ yield flowResult(
734
+ this.execute(
735
+ 'executeTests',
736
+ {
737
+ path,
738
+ relevantTestsOnly,
739
+ },
740
+ false,
741
+ async (result: ExecutionResult) => {
742
+ const refreshTreesPromise = flowResult(this.refreshTrees());
743
+ if (result instanceof ExecutionFailureResult) {
744
+ await flowResult(
745
+ this.loadFile(
746
+ result.source,
747
+ new FileCoordinate(
748
+ result.source,
749
+ result.line,
750
+ result.column,
751
+ result.text.split('\n').filter(Boolean)[0],
752
+ ),
753
+ ),
754
+ );
755
+ this.setActiveAuxPanelMode(AUX_PANEL_MODE.CONSOLE);
756
+ this.auxPanelDisplayState.open();
757
+ this.testRunState.fail();
758
+ } else if (result instanceof TestExecutionResult) {
759
+ this.setActiveAuxPanelMode(AUX_PANEL_MODE.TEST_RUNNER);
760
+ this.auxPanelDisplayState.open();
761
+ const testRunnerState = new TestRunnerState(this, result);
762
+ this.setTestRunnerState(testRunnerState);
763
+ await flowResult(testRunnerState.buildTestTreeData());
764
+ // make sure we refresh tree so it is shown in the explorer panel
765
+ // NOTE: we could potentially expand the tree here, but this operation is expensive since we have all nodes observable
766
+ // so it will lag the UI if we have too many nodes open
767
+ testRunnerState.refreshTree();
768
+ await flowResult(testRunnerState.pollTestRunnerResult());
769
+ this.testRunState.pass();
770
+ }
771
+ // do nothing?
772
+ await refreshTreesPromise;
773
+ },
774
+ ),
775
+ );
776
+ }
777
+
778
+ *executeFullTestSuite(relevantTestsOnly?: boolean): GeneratorFn<void> {
779
+ yield flowResult(this.executeTests('::', relevantTestsOnly));
780
+ }
781
+
782
+ *executeNavigation(coordinate: FileCoordinate): GeneratorFn<void> {
783
+ this.navigationStack.push(coordinate);
784
+ yield flowResult(
785
+ this.execute(
786
+ 'getConcept',
787
+ {
788
+ file: coordinate.file,
789
+ line: coordinate.line,
790
+ column: coordinate.column,
791
+ },
792
+ false,
793
+ async (result: ExecutionResult) => {
794
+ if (result instanceof GetConceptResult) {
795
+ await flowResult(
796
+ this.loadFile(
797
+ result.jumpTo.source,
798
+ new FileCoordinate(
799
+ result.jumpTo.source,
800
+ result.jumpTo.line,
801
+ result.jumpTo.column,
802
+ ),
803
+ ),
804
+ );
805
+ }
806
+ },
807
+ ),
808
+ );
809
+ }
810
+
811
+ *navigateBack(): GeneratorFn<void> {
812
+ if (this.navigationStack.length === 0) {
813
+ this.applicationStore.notifyWarning(
814
+ `Can't navigate back any further - navigation stack is empty`,
815
+ );
816
+ return;
817
+ }
818
+ if (this.navigationStack.length > 0) {
819
+ const coordinate = this.navigationStack.pop();
820
+ if (coordinate) {
821
+ yield flowResult(this.loadFile(coordinate.file, coordinate));
822
+ }
823
+ }
824
+ }
825
+
826
+ *executeSaveAndReset(fullInit: boolean): GeneratorFn<void> {
827
+ yield flowResult(
828
+ this.execute(
829
+ 'executeSaveAndReset',
830
+ {},
831
+ true,
832
+ async (result: ExecutionResult) => {
833
+ this.initState.reset();
834
+ await flowResult(
835
+ this.initialize(
836
+ fullInit,
837
+ undefined,
838
+ this.client.mode,
839
+ this.client.compilerMode,
840
+ ),
841
+ );
842
+ this.setActiveActivity(ACTIVITY_MODE.CONCEPT, {
843
+ keepShowingIfMatchedCurrent: true,
844
+ });
845
+ },
846
+ ),
847
+ );
848
+ }
849
+
850
+ *fullReCompile(fullInit: boolean): GeneratorFn<void> {
851
+ this.applicationStore.setActionAlertInfo({
852
+ message: 'Are you sure you want to perform a full re-compile?',
853
+ prompt: 'This may take a long time to complete',
854
+ type: ActionAlertType.CAUTION,
855
+ actions: [
856
+ {
857
+ label: 'Perform full re-compile',
858
+ type: ActionAlertActionType.PROCEED_WITH_CAUTION,
859
+ handler: () => {
860
+ flowResult(this.executeSaveAndReset(fullInit)).catch(
861
+ this.applicationStore.alertUnhandledError,
862
+ );
863
+ },
864
+ },
865
+ {
866
+ label: 'Abort',
867
+ type: ActionAlertActionType.PROCEED,
868
+ default: true,
869
+ },
870
+ ],
871
+ });
872
+ }
873
+
874
+ *refreshTrees(): GeneratorFn<void> {
875
+ yield Promise.all([
876
+ this.directoryTreeState.refreshTreeData(),
877
+ this.conceptTreeState.refreshTreeData(),
878
+ ]);
879
+ }
880
+
881
+ *updateFileUsingSuggestionCandidate(
882
+ candidate: CandidateWithPackageNotImported,
883
+ ): GeneratorFn<void> {
884
+ this.setSearchState(undefined);
885
+ yield flowResult(
886
+ this.updateFile(
887
+ candidate.fileToBeModified,
888
+ candidate.lineToBeModified,
889
+ candidate.columnToBeModified,
890
+ candidate.add,
891
+ candidate.messageToBeModified,
892
+ ),
893
+ );
894
+ this.setActiveAuxPanelMode(AUX_PANEL_MODE.CONSOLE);
895
+ this.auxPanelDisplayState.open();
896
+ }
897
+
898
+ *updateFile(
899
+ path: string,
900
+ line: number,
901
+ column: number,
902
+ add: boolean,
903
+ message: string,
904
+ ): GeneratorFn<void> {
905
+ yield flowResult(
906
+ this.execute(
907
+ 'updateSource',
908
+ {
909
+ updatePath: path,
910
+ updateSources: [
911
+ {
912
+ path,
913
+ line,
914
+ column,
915
+ add,
916
+ message,
917
+ },
918
+ ],
919
+ },
920
+ false,
921
+ (result: ExecutionResult) =>
922
+ flowResult(this.manageExecuteGoResult(result)),
923
+ ),
924
+ );
925
+ }
926
+
927
+ *searchFile(): GeneratorFn<void> {
928
+ if (this.fileSearchCommandLoadingState.isInProgress) {
929
+ return;
930
+ }
931
+ this.fileSearchCommandLoadingState.inProgress();
932
+ this.fileSearchCommandResults = (yield this.client.findFiles(
933
+ this.fileSearchCommandState.text,
934
+ this.fileSearchCommandState.isRegExp,
935
+ )) as string[];
936
+ this.fileSearchCommandLoadingState.pass();
937
+ }
938
+
939
+ *searchText(): GeneratorFn<void> {
940
+ if (this.textSearchCommandLoadingState.isInProgress) {
941
+ return;
942
+ }
943
+ this.textSearchCommandLoadingState.inProgress();
944
+ this.setActiveAuxPanelMode(AUX_PANEL_MODE.SEARCH_RESULT);
945
+ this.auxPanelDisplayState.open();
946
+ try {
947
+ const results = (
948
+ (yield this.client.searchText(
949
+ this.textSearchCommandState.text,
950
+ this.textSearchCommandState.isCaseSensitive,
951
+ this.textSearchCommandState.isRegExp,
952
+ )) as PlainObject<SearchResultEntry>[]
953
+ ).map((result) => getSearchResultEntry(result));
954
+ this.setSearchState(new SearchResultState(this, results));
955
+ this.textSearchCommandLoadingState.pass();
956
+ } catch (error) {
957
+ assertErrorThrown(error);
958
+ this.applicationStore.notifyError(error);
959
+ this.textSearchCommandLoadingState.fail();
960
+ }
961
+ }
962
+
963
+ *findUsages(coordinate: FileCoordinate): GeneratorFn<void> {
964
+ const errorMessage =
965
+ 'Error finding references. Please make sure that the code compiles and that you are looking for references of non primitive types!';
966
+ let concept: UsageConcept;
967
+ try {
968
+ concept = (yield this.client.getConceptPath(
969
+ coordinate.file,
970
+ coordinate.line,
971
+ coordinate.column,
972
+ )) as UsageConcept;
973
+ } catch {
974
+ this.applicationStore.notifyWarning(errorMessage);
975
+ return;
976
+ }
977
+ try {
978
+ this.applicationStore.setBlockingAlert({
979
+ message: 'Finding concept usages...',
980
+ prompt: `Finding references of ${getUsageConceptLabel(concept)}`,
981
+ showLoading: true,
982
+ });
983
+ const usages = (
984
+ (yield this.client.getUsages(
985
+ concept.owner
986
+ ? concept.type
987
+ ? 'meta::pure::ide::findusages::findUsagesForEnum_String_1__String_1__SourceInformation_MANY_'
988
+ : 'meta::pure::ide::findusages::findUsagesForProperty_String_1__String_1__SourceInformation_MANY_'
989
+ : 'meta::pure::ide::findusages::findUsagesForPath_String_1__SourceInformation_MANY_',
990
+ (concept.owner ? [`'${concept.owner}'`] : []).concat(
991
+ `'${concept.path}'`,
992
+ ),
993
+ )) as PlainObject<Usage>[]
994
+ ).map((usage) => deserialize(Usage, usage));
995
+ this.setSearchState(new UsageResultState(this, concept, usages));
996
+ this.setActiveAuxPanelMode(AUX_PANEL_MODE.SEARCH_RESULT);
997
+ this.auxPanelDisplayState.open();
998
+ } catch {
999
+ this.applicationStore.notifyWarning(errorMessage);
1000
+ } finally {
1001
+ this.applicationStore.setBlockingAlert(undefined);
1002
+ }
1003
+ }
1004
+
1005
+ *command(
1006
+ cmd: () => Promise<PlainObject<CommandResult>>,
1007
+ ): GeneratorFn<boolean> {
1008
+ try {
1009
+ const result = deserializeCommandResult(
1010
+ (yield cmd()) as PlainObject<CommandResult>,
1011
+ );
1012
+ if (result instanceof CommandFailureResult) {
1013
+ if (result.errorDialog) {
1014
+ this.applicationStore.notifyWarning(`Error: ${result.text}`);
1015
+ } else {
1016
+ this.setConsoleText(result.text);
1017
+ }
1018
+ return false;
1019
+ }
1020
+ return true;
1021
+ } catch (error) {
1022
+ assertErrorThrown(error);
1023
+ this.applicationStore.notifyError(error);
1024
+ return false;
1025
+ }
1026
+ }
1027
+
1028
+ *createNewDirectory(path: string): GeneratorFn<void> {
1029
+ yield flowResult(
1030
+ this.command(() => this.client.createFolder(trimPathLeadingSlash(path))),
1031
+ );
1032
+ yield flowResult(this.directoryTreeState.refreshTreeData());
1033
+ }
1034
+
1035
+ *createNewFile(path: string): GeneratorFn<void> {
1036
+ const result = (yield flowResult(
1037
+ this.command(() => this.client.createFile(trimPathLeadingSlash(path))),
1038
+ )) as boolean;
1039
+ yield flowResult(this.directoryTreeState.refreshTreeData());
1040
+ if (result) {
1041
+ yield flowResult(this.loadFile(path));
1042
+ }
1043
+ }
1044
+
1045
+ *deleteDirectoryOrFile(
1046
+ path: string,
1047
+ isDirectory: boolean,
1048
+ hasChildContent: boolean,
1049
+ ): GeneratorFn<void> {
1050
+ const _delete = async (): Promise<void> => {
1051
+ await flowResult(
1052
+ this.command(() =>
1053
+ this.client.deleteDirectoryOrFile(trimPathLeadingSlash(path)),
1054
+ ),
1055
+ );
1056
+ const editorStatesToClose = this.tabManagerState.tabs.filter(
1057
+ (tab) =>
1058
+ tab instanceof FileEditorState && tab.filePath.startsWith(path),
1059
+ );
1060
+ editorStatesToClose.forEach((tab) => this.tabManagerState.closeTab(tab));
1061
+ await flowResult(this.directoryTreeState.refreshTreeData());
1062
+ };
1063
+ this.applicationStore.setActionAlertInfo({
1064
+ message: `Are you sure you would like to delete this ${
1065
+ isDirectory ? 'directory' : 'file'
1066
+ }?`,
1067
+ prompt: hasChildContent
1068
+ ? 'Beware! This directory is not empty, this action is not undo-able, you have to manually revert using VCS'
1069
+ : 'Beware! This action is not undo-able, you have to manually revert using VCS',
1070
+ type: ActionAlertType.CAUTION,
1071
+ actions: [
1072
+ {
1073
+ label: 'Delete anyway',
1074
+ type: ActionAlertActionType.PROCEED_WITH_CAUTION,
1075
+ handler: () => {
1076
+ _delete().catch(this.applicationStore.alertUnhandledError);
1077
+ },
1078
+ },
1079
+ {
1080
+ label: 'Abort',
1081
+ type: ActionAlertActionType.PROCEED,
1082
+ default: true,
1083
+ },
1084
+ ],
1085
+ });
1086
+ }
1087
+ }