/
HopscotchWebIDE.ns
476 lines (463 loc) · 19.7 KB
/
HopscotchWebIDE.ns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
Newspeak3
'Root'
class HopscotchWebIDE packageUsing: manifest = (
(* The Newspeak IDE in the web browser. *)
|
private Browsing = manifest Browsing.
private CombinatorialParsing = manifest CombinatorialParsing.
private Debugging = manifest Debugging.
private DeploymentManager = manifest DeploymentManager.
private MetadataParsing = manifest MetadataParsing.
private Minitest = manifest Minitest.
private MinitestUI = manifest MinitestUI.
private Namespacing = manifest Namespacing.
private NewspeakColorization = manifest NewspeakColorization.
private NewspeakGrammar = manifest NewspeakGrammar.
private NewspeakASTs = manifest NewspeakASTs.
private NewspeakParsing = manifest NewspeakParsing.
private Documents = manifest Documents.
private DocumentHolder = manifest DocumentHolder.
private WorkspaceHolder = manifest WorkspaceHolder.
private WorkspaceManager = manifest WorkspaceManager.
private RuntimeForPrimordialSoup = manifest RuntimeForPrimordialSoup.
private RuntimeWithMirrorsForPrimordialSoup = manifest RuntimeWithMirrorsForPrimordialSoup.
private WebCompiler = manifest WebCompiler.
(* Web stuff *)
private WebFiles = manifest WebFiles.
private JSON = manifest JSON.
(* JS stuff *)
private NewspeakCompilation = manifest NewspeakCompilation.
private JavascriptGeneration = manifest JavascriptGeneration.
private Newspeak2JSCompilation = manifest Newspeak2JSCompilation.
private ActorsForJS = manifest ActorsForJS.
private AliensForJS = manifest AliensForJS.
private MirrorsForJS = manifest MirrorsForJS.
private MirrorGroups = manifest MirrorGroups.
private KernelForJS = manifest KernelForJS.
private Collections = manifest Collections.
private Streams = manifest Streams.
private RuntimeForElectron = manifest RuntimeForElectron.
private RuntimeForHopscotchForHTML = manifest RuntimeForHopscotchForHTML.
private RuntimeForJS = manifest RuntimeForJS.
private RuntimeForJSWithMirrorBuilders = manifest RuntimeForJSWithMirrorBuilders.
private testModules = {
manifest AccessModifierTesting.
manifest AccessModifierTestingConfiguration.
manifest KernelTests.
manifest KernelTestsConfiguration.
manifest MinitestTests.
manifest MinitestTestsConfiguration.
manifest MirrorTesting.
manifest MirrorTestingConfiguration.
manifest MirrorTestingModel.
manifest MirrorBuilderTesting.
manifest MirrorBuilderTestingConfiguration.
manifest ActivationMirrorTesting.
manifest ActivationMirrorTestingConfiguration.
manifest JSTesting.
manifest JSTestingConfiguration.
}.
private imagesOuter = HopscotchImages packageUsing: manifest. (* Should be `images` but there appears to be an outer send bug in NS2JS. *)
private standardNames <Set[String]>
private standardIconNames <Set[String]>
|
(* manifest codemirror.*)
) (
class HopscotchImages packageUsing: manifest = (
|
public accept16px = manifest accept16px.
public addImage = manifest hsAddImage.
public ampleforthDocument = manifest ampleforthDocument.
public backImage = manifest hsBackImage.
public cancel16px = manifest cancel16px.
public classIcon = manifest languageNewspeak3.
public classPresenterIcon = manifest classPresenterImage.
public classUnknownIcon = manifest classUnknownImage.
public clearImage = manifest clearImage.
public collapseImage = manifest hsCollapseImage.
public disclosureClosedImage = manifest disclosureClosedImage.
public disclosureOpenImage = manifest disclosureOpenImage.
public downloadImage = manifest downloadImage.
public dropDownImage = manifest hsDropdownImage.
public expandImage = manifest hsExpandImage.
public findImage = manifest findImage.
public forwardImage = manifest hsForwardImage.
public helpImage = manifest helpImage.
public historyImage = manifest hsHistoryImage.
public homeImage = manifest hsHomeImage.
public itemReferencesImage = manifest itemReferencesImage.
public newImage = manifest hsNewImage.
public peekingeye1610 = manifest peekingeye1610.
public privateAccessImage = manifest privateImage.
public protectedAccessImage = manifest protectedImage.
public publicAccessImage = manifest publicImage.
public refreshImage = manifest hsRefreshImage.
public saveImage = manifest saveImage.
public sectionImage = manifest sectionImage.
|) (
) : (
)
class RestoreDialog usingPlatform: p = (
|
private List = p collections List.
private Presenter = p hopscotch Presenter.
private Subject = p hopscotch Subject.
window = p hopscotch HopscotchWindow openSubject: (RestoreDialogSubject onModel: p).
|
) (
public class RestoreDialogSubject onModel: p = Subject onModel: p () (
public isKindOfRestoreDialogSubject ^ <Boolean> = (^true)
isMyKind: other <Subject> ^ <Boolean> = (
^other isKindOfRestoreDialogSubject
)
public createPresenter = (^RestoreDialogPresenter onSubject: self)
public loadSaved = (
window exit.
setupIDEWith: (loadFrom: #lastSaved usingPlatform: model) using: model
)
public restoreBackup = (
window exit.
setupIDEWith: (loadFrom: #backup usingPlatform: model) using: model
)
public useCurrent = (
window exit.
setupIDEWith: List new using: model
)
public title ^ <String> = (
^'Newspeak IDE'
)
) : (
)
class RestoreDialogPresenter onSubject: s = Presenter onSubject: s () (
public isKindOfRestoreDialogPresenter ^ <Boolean> = (^true)
isMyKind: other <Fragment> ^ <Boolean> = (
^other isKindOfRestoreDialogPresenter
)
definition = (
^column: {
label: 'You have backup changes that are newer than your last save. Do you want to restore these changes, or load from the last save?'.
row: {
button: 'Restore from backup' action: [subject restoreBackup].
button: 'Load older saved version' action: [subject loadSaved].
button: 'Use current version, ignoring both saved and backup versions' action: [subject useCurrent]
}
}
)
) : (
)
) : (
)
class HopscotchWebIDE usingPlatform: p = (
|
public Map = p collections Map.
public images = imagesOuter.
public browsing = Browsing usingPlatform: p ide: self.
public debugging = Debugging usingPlatform: p ide: self.
public namespacing = Namespacing usingPlatform: p.
public workspaceHolder = WorkspaceHolder usingPlatform: p ide: self.
public theWorkspaceManager = WorkspaceManager usingPlatform: p ide: self.
public documents = Documents usingPlatform: p ide: self.
public documentHolder = DocumentHolder usingDocumentClass: documents Document ide: self.
public minitest = Minitest usingPlatform: p.
public minitestUI = MinitestUI usingPlatform: p minitest: minitest ide: self.
public parserLib = CombinatorialParsing usingPlatform: p.
public grammar = NewspeakGrammar usingPlatform: p parsers: parserLib.
public colorizer = (NewspeakColorization usingPlatform: p grammar: grammar) NS3BrowserColorizer new.
public webFiles = WebFiles usingPlatform: p.
public json = JSON usingPlatform: p.
public deployment
public psoupDeploymentRuntime = RuntimeForPrimordialSoup.
public psoupWithMirrorsDeploymentRuntime = RuntimeWithMirrorsForPrimordialSoup.
public psoupWithHopscotchDeploymentRuntime = RuntimeForHopscotchForHTML.
public localStorage = (p js global at: 'window') at: 'localStorage'.
public atomicInstaller = p mirrors installer.
Date = p js global at: 'Date'.
version_slot ::= maxStoredVersion.
|
populateNamespaceUsingPlatform: p.
deployment:: DeploymentManager usingPlatform: p ide: self.
) (
public launch: s <Subject> inWindow: w <HopscotchShell class> = (
browsing launch: s inWindow: w
)
public launch: s <Subject> = (
browsing launch: s inWindow: browsing IDEWindow
)
backup ^ <Map[Symbol, String]> = (
^[json decode: (localStorage getItem: #backup)] on: Error do: [:e | Map new].
)
topMostBuilderOf: b <ClassDeclarationBuilder> ^ <ClassDeclarationBuilder> = (
| outermost <ClassDeclarationBuilder> ::= b. |
[nil = outermost enclosingClass] whileFalse:
[outermost:: outermost enclosingClass].
^outermost
)
public incrementedVersion = (
^version_slot:: version_slot + 1.
)
public installFromBuilders: bs <Array[ClassDeclarationBuilder]> ^ <List[MixinMirror]> = (
(* A centralized method for installing new code from the IDE *)
^installFromBuilders: bs into: namespacing Root.
)
public installFromBuilders: bs <Array[ClassDeclarationBuilder]> into: namespace <Map[Symbol, Object]> ^ <List[MixinMirror]> = (
(* A centralized method for installing new code from the IDE *)
|
lastBackup <Map[Symbol, String]> = backup.
(* Make sure all builders are top level *)
builders <Array[ClassDeclarationBuilder]> = bs collect: [:b <ClassDeclartionBuilder> | topMostBuilderOf: b].
(* Install the code *)
mixins = atomicInstaller install: builders into: namespace.
|
(* Backup the changes *)
builders do: [:b <ClassDeclarationBuilder> |
(* Add each changed module to the backup *)
lastBackup at: b name put: (browsing compilationUnitFromSource: b source)
].
(* Save new backup in local storage *)
localStorage setItem: #backup to: (json encode: lastBackup).
(* Timestamp latest backup *)
localStorage setItem: #lastBackupTime to: incrementedVersion.
^mixins
)
lastBackupTime ^ <Integer> = (
| backupString <String> = [localStorage getItem: #lastBackupTime] on: Error do: [:e | '0']. |
^Integer parse: (backupString isNil ifFalse: [backupString] ifTrue: ['0']) radix: 10.
)
lastSavedTime ^ <Integer> = (
| savedString <String> = [localStorage getItem: #lastSavedTime] on: Error do: [:e | '0']. |
^Integer parse: (savedString isNil ifFalse: [savedString] ifTrue: ['0']) radix: 10.
)
maxStoredVersion ^ <Integer> = (
^lastSavedTime max: lastBackupTime
)
public standardPreludeIconNames ^ <List[String]> = (
^standardIconNames
)
public standardPreludeMessages ^ <List[String]> = (
^standardNames
)
populateNamespaceUsingPlatform: p <Platform> ^ <Namespace> = (
|
platformMirror <ObjectMirror> = p mirrors ObjectMirror reflecting: p.
runtimeClass <ClassMirror> = topLevelClassOf: platformMirror.
namespace <Namespace> = namespacing Root.
|
namespace
at: 'Icons' put: (populateIconNamespace: namespacing freshNamespace);
at: runtimeClass mixin name put: runtimeClass reflectee;
at: 'Browsing' put: Browsing;
at: 'Minitest' put: Minitest;
at: 'MinitestUI' put: MinitestUI;
at: 'Namespacing' put: Namespacing;
at: 'NewspeakColorization' put: NewspeakColorization;
at: 'HopscotchWebIDE' put: (topLevelClassOf: (p mirrors ObjectMirror reflecting: self)) reflectee;
at: 'CombinatorialParsing' put: CombinatorialParsing;
at: 'NewspeakGrammar' put: NewspeakGrammar;
at: 'NewspeakASTs' put: NewspeakASTs;
at: 'NewspeakParsing' put: NewspeakParsing;
at: 'MetadataParsing' put: MetadataParsing;
at: 'Debugging' put: Debugging;
at: 'Documents' put: Documents;
at: 'DocumentHolder' put: DocumentHolder;
at: 'WorkspaceManager' put: WorkspaceManager;
at: 'WorkspaceHolder' put: WorkspaceHolder;
at: 'DeploymentManager' put: DeploymentManager;
at: 'RuntimeForPrimordialSoup' put: RuntimeForPrimordialSoup;
at: 'RuntimeWithMirrorsForPrimordialSoup' put: RuntimeWithMirrorsForPrimordialSoup;
at: 'RuntimeForElectron' put: RuntimeForElectron;
at: 'RuntimeForHopscotchForHTML' put: RuntimeForHopscotchForHTML;
at: 'RuntimeForJS' put: RuntimeForJS;
at: 'RuntimeForJSWithMirrorBuilders' put: RuntimeForJSWithMirrorBuilders;
at: 'NewspeakCompilation' put: NewspeakCompilation;
at: 'JavascriptGeneration' put: JavascriptGeneration;
at: 'JSON' put: JSON;
at: 'Newspeak2JSCompilation' put: Newspeak2JSCompilation;
at: 'KernelForJS' put: KernelForJS;
at: 'ActorsForJS' put: ActorsForJS;
at: 'AliensForJS' put: AliensForJS;
at: 'MirrorsForJS' put: MirrorsForJS;
at: 'MirrorGroups' put: MirrorGroups;
at: 'Collections' put: Collections;
at: 'Streams' put: Streams;
at: 'WebCompiler' put: WebCompiler;
at: 'WebFiles' put: WebFiles.
testModules do: [:testModule | namespace at: testModule name put: testModule].
augmentIDE: self withPlatform: p.
^namespace
)
populateIconNamespace: ns <Namespace> ^ <Namespace> = (
^ns
at: 'accept16px' put: images accept16px;
at: 'ampleforthDocument' put: images ampleforthDocument;
at: 'cancel16px' put: images cancel16px;
at: 'clearImage' put: images clearImage;
at: 'disclosureClosedImage' put: images disclosureClosedImage;
at: 'disclosureOpenImage' put: images disclosureOpenImage;
at: 'downloadImage' put: images downloadImage;
at: 'helpImage' put: images helpImage;
at: 'publicImage' put: images publicAccessImage;
at: 'protectedImage' put: images protectedAccessImage;
at: 'privateImage' put: images privateAccessImage;
at: 'hsAddImage' put: images addImage;
at: 'hsBackImage' put: images backImage;
at: 'hsDropdownImage' put: images dropDownImage;
at: 'hsExpandImage' put: images expandImage;
at: 'hsCollapseImage' put: images collapseImage;
at: 'classPresenterImage' put: images classPresenterIcon;
at: 'classUnknownImage' put: images classUnknownIcon;
at: 'hsForwardImage' put: images forwardImage;
at: 'languageNewspeak3' put: images classIcon;
at: 'itemReferencesImage' put: images itemReferencesImage;
at: 'hsHistoryImage' put: images historyImage;
at: 'hsHomeImage' put: images homeImage;
at: 'hsNewImage' put: images newImage;
at: 'hsRefreshImage' put: images refreshImage;
at: 'findImage' put: images findImage;
at: 'peekingeye1610' put: images peekingeye1610;
at: 'saveImage' put: images saveImage;
at: 'sectionImage' put: images sectionImage;
yourself
)
public setupNames = (
(* Record standard namespace names *)
standardNames:: namespacing Root keys.
(* Record standard icon names *)
standardIconNames:: (namespacing Root at: #Icons) keys.
)
) : (
)
public augmentIDE: ide withPlatform: p = (
|
platformMirror <ObjectMirror> = p mirrors ObjectMirror reflecting: p.
platformClass <ClassMirror> = platformMirror getClass.
runtimeMirror<ObjectMirror> = platformClass enclosingObject.
runtimeClass <ClassMirror> = topLevelClassOf: platformMirror.
namespace <Namespace> = ide namespacing Root.
|
runtimeClass slots do:
[:s <SlotMirror> | | klass <ClassMirror> o <Object> |
o:: (runtimeMirror getSlot: s name) reflectee.
o isKindOfBehavior ifTrue:
[namespace at: o name put: o]].
)
topLevelClassOf: om <ObjectMirror> ^ <ClassMirror> = (
| klass <ClassMirror> ::= om getClass. |
[klass enclosingObject reflectee isNil] whileFalse: [klass:: klass enclosingObject getClass].
^klass
)
loadOrRestoreUsingPlatform: p = (
|
localStorage<Alien[LocalStorage]> = (p js global at: 'window') at: 'localStorage'.
lastBackupTime = Integer parse: ([localStorage getItem: #lastBackupTime] on: Error do: [:e | 0]) radix: 10.
lastSavedTime = Integer parse: ([localStorage getItem: #lastSavedTime] on: Error do: [:e | 0]) radix: 10.
|
lastBackupTime > lastSavedTime
ifTrue: [RestoreDialog usingPlatform: p]
ifFalse: [setupIDEWith: (loadFrom: #lastSaved usingPlatform: p) using: p]
)
public augmentNamespace: namespace withPlatform: p = (
|
platformMirror <ObjectMirror> = p mirrors ObjectMirror reflecting: p.
platformClass <ClassMirror> = platformMirror getClass.
runtimeMirror<ObjectMirror> = platformClass enclosingObject.
runtimeClass <ClassMirror> = topLevelClassOf: platformMirror.
|
runtimeClass slots do:
[:s <SlotMirror> | | klass <ClassMirror> o <Object> |
o:: (runtimeMirror getSlot: s name) reflectee.
o isKindOfBehavior ifTrue:
[namespace at: o name put: o]].
)
ensureLocalStorage: localStorage = (
(localStorage getItem: #lastBackupTime) isNil ifTrue: [
localStorage setItem: #lastBackupTime to: 0.
].
(localStorage getItem: #backup) isNil ifTrue: [
localStorage setItem: #backup to: '{}'.
].
(localStorage getItem: #lastSavedTime) isNil ifTrue: [
localStorage setItem: #lastSavedTime to: 0.
].
(localStorage getItem: #lastSaved) isNil ifTrue: [
localStorage setItem: #lastSaved to: '{}'.
].
)
loadFrom: lsKey <Symbol> usingPlatform: p ^ <List[MixinMirror]> = (
[ |
json = JSON usingPlatform: p.
localStorage = (p js global at: 'window') at: 'localStorage'.
recoveredMap <Map[String]| Nil> = json decode: ([localStorage getItem: lsKey] on: Error do: [:e | nil]).
recoveredCode = recoveredMap isNil ifFalse: [recoveredMap values] ifTrue: [p collections List new].
bs <List[ClassDeclarationBuilder]> = recoveredCode collect: [:s <String> |
p mirrors ClassDeclarationBuilder fromUnitSource: s
].
forbidden <Set[Symbol]> = p collections Set withAll: {#HopscotchWebIDE. #KernelForPrimordialSoup}.
filtered = bs reject: [:b | forbidden includes: b name].
mixins <List[MixinMirror]> = p mirrors installer install: filtered into: (namespaceGivenPlatform: p).
|
^mixins
] on: Error do: [:msg | msg out. nil].
^p collections List new
)
public ideUsingPlatform: p = (
(* The call to ensureLocalStorage: is usually redundant, except when other tools embed the IDE using
this method as the entry point. *)
ensureLocalStorage: ((p js global at: 'window') at: 'localStorage').
^HopscotchWebIDE usingPlatform: p
)
public main: platform <Platform> args: args <Tuple[String]> = (
| ide |
ensureLocalStorage:: (platform js global at: 'window') at: 'localStorage'.
(platform js global at: 'document') at: 'title' put: 'Newspeak IDE'.
loadOrRestoreUsingPlatform: platform
)
namespaceGivenPlatform: p ^ <Map[Symbol, Object]> = (
|
platformMirror <ObjectMirror> = p mirrors ObjectMirror reflecting: p.
runtimeClass <ClassMirror> = topLevelClassOf: platformMirror.
ns = p collections Map new.
|
ns at: runtimeClass mixin name put: runtimeClass reflectee;
at: 'Browsing' put: Browsing;
at: 'Minitest' put: Minitest;
at: 'MinitestUI' put: MinitestUI;
at: 'Namespacing' put: Namespacing;
at: 'NewspeakColorization' put: NewspeakColorization;
at: 'CombinatorialParsing' put: CombinatorialParsing;
at: 'NewspeakGrammar' put: NewspeakGrammar;
at: 'NewspeakASTs' put: NewspeakASTs;
at: 'NewspeakParsing' put: NewspeakParsing;
at: 'Debugging' put: Debugging;
at: 'WorkspaceManager' put: WorkspaceManager;
at: 'DeploymentManager' put: DeploymentManager;
at: 'RuntimeForPrimordialSoup' put: RuntimeForPrimordialSoup;
at: 'RuntimeWithMirrorsForPrimordialSoup' put: RuntimeWithMirrorsForPrimordialSoup;
at: 'RuntimeForElectron' put: RuntimeForElectron;
at: 'RuntimeForHopscotchForHTML' put: RuntimeForHopscotchForHTML;
at: 'RuntimeForJS' put: RuntimeForJS;
at: 'RuntimeForJSWithMirrorBuilders' put: RuntimeForJSWithMirrorBuilders;
at: 'NewspeakCompilation' put: NewspeakCompilation;
at: 'JavascriptGeneration' put: JavascriptGeneration;
at: 'Newspeak2JSCompilation' put: Newspeak2JSCompilation;
at: 'KernelForJS' put: KernelForJS;
at: 'ActorsForJS' put: ActorsForJS;
at: 'AliensForJS' put: AliensForJS;
at: 'MirrorsForJS' put: MirrorsForJS;
at: 'MirrorGroups' put: MirrorGroups;
at: 'Collections' put: Collections;
at: 'Streams' put: Streams;
at: 'WebCompiler' put: WebCompiler;
at: 'WebFiles' put: WebFiles.
testModules do: [:testModule | ns at: testModule name put: testModule].
augmentNamespace: ns withPlatform: p.
^ns
)
setupIDEWith: mixins using: platform = (
| ide = ideUsingPlatform: platform. |
augmentIDE: ide withPlatform: platform local.
ide setupNames.
mixins do: [:m <MixinMirror> | ide namespacing Root at: m name put: m declaration applyToObject reflectee].
ide launch: (ide browsing HomeSubject new)
)
) : (
)