-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathAmpleforthEmbedder.ns
174 lines (170 loc) · 6.04 KB
/
AmpleforthEmbedder.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
Newspeak3
'Root'
class AmpleforthEmbedder usingPlatform: p ide: webIDE = (
(*
Ampleforth is designed to support live literate programming. It supports embedding Newspeak code inside the text of a normal web page. This code pertains to an earlier version of Ampleforth. See the comments in Ampleforth.ns for more details about the difference between the two.
Ampleforth documents can be produced by editing HTML in any tool. Use the Ampleforth application to run such pages stand alone. One can interactively edit and run such documents in the Newspeak IDE (see the HopscotchWebIDE module).
Ampleforth is a character in 1984 whose role is to convert works of Oldspeak literature into Newspeak. He's a literary editor conversant in Newspeak.
Copyright 2014-2017 Google Inc.
Copyright 2022-2024 Gilad Bracha.
*)
|
private List = p collections List.
private Color = p graphics Color.
private ObjectMirror = p mirrors ObjectMirror.
private ClassMirror = p mirrors ClassMirror.
private Subject = p hopscotch core Subject.
private Presenter = p hopscotch core Presenter.
private TextEditorFragment = p hopscotch fragments TextEditorFragment.
private Gradient = p hopscotch Gradient.
private EmbeddedHopscotchWindow = p hopscotch core EmbeddedHopscotchWindow.
private ClassSubject = webIDE browsing ClassSubject.
private EvaluationViewState = webIDE browsing EvaluationViewState.
private EvaluatorSubject = webIDE browsing EvaluatorSubject.
private HomeSubject = webIDE browsing HomeSubject.
private ObjectSubject = webIDE browsing ObjectSubject.
private IDEWindow = webIDE browsing IDEWindow.
private Document = webIDE documents Document.
EmbeddedIDEWindow = IDEWindow mixinApply: EmbeddedHopscotchWindow.
namespace = webIDE namespacing Root.
browsing = webIDE browsing.
document = p js global at: 'document'.
platformMirror = ObjectMirror reflecting: p.
|
namespace at: #AmpleforthEmbedder put: self class
) (
class ErrorPresenter onSubject: s = Presenter onSubject: s (
) (
public definition ^ <Fragment> = (
^label: subject errorMessage
)
public isKindOfErrorPresenter ^ <Boolean> = (
^true
)
isMyKind: f <Fragment> ^ <Boolean> = (
^f isKindOfErrorPresenter
)
) : (
)
class ErrorSubject onModel: s <String> = Subject onModel: s (
|
public errorMessage = s.
|) (
public createPresenter ^ <ErrorPresenter> = (
^ErrorPresenter onSubject: self
)
isMyKind: other ^ <Boolean> = (
^other isKindOfErrorSubject
)
public isKindOfErrorSubject ^ <Boolean> = (
^true
)
) : (
)
domElementsWithClass: klass <String> do: action <[:Alien[Element]]> = (
| elements = document getElementsByClassName: klass. |
0 to: (elements at: 'length') - 1 do:
[:index | action value: (elements at: index)].
)
evaluateSubject: se <String> ^ <Subject> = (
(* Takes a string representing a unary block and evaluates it with
browsing as its argument. The result should be a Subject, which gets
returned. In other words, the string should contain an expression of type
[:BrowsingForHTML | Subject]
*)
| blk |
blk:: platformMirror
evaluate: (withoutNbsp: se)
ifCompilerError: [:e | ^ErrorSubject onModel: 'compile-time error: ', e printString]
ifError: [:e | ^ErrorSubject onModel: 'runtime error: ', e printString].
^blk value: browsing
)
topLevelClassOf: om <ObjectMirror> ^ <ClassDeclarationMirror> = (
| klass ::= om getClass mixin declaration. |
[klass mixin enclosingClass isNil] whileFalse: [klass:: klass enclosingClass].
^klass
)
withoutNbsp: string = (
('a' at: 1) isKindOfInteger
ifTrue:
[ | bytes = ByteArray withAll: string. |
1 to: bytes size do: [:index | (bytes at: index) = 160 ifTrue: [bytes at: index put: 32]].
^bytes asString]
ifFalse:
[ | nonbreakingSpace = String fromRune: 160.
space = String fromRune: 32. |
^string replaceAll: nonbreakingSpace with: space]
)
populateNamespace = (
| platformClass <ClassMirror> = topLevelClassOf: platformMirror. |
namespace at: #Browsing put: (ClassMirror reflecting: self Browsing) mixin declaration.
namespace at: platformClass name put: platformClass.
platformClass slots do: [:s <SlotMirror> | | klass <ClassMirror> o <ObjectMirror> |
o:: platformMirror getSlot: s name.
klass:: topLevelClassOf: o.
namespace at: klass name put: klass.
].
)
public processEvaluators = (
domElementsWithClass: 'evaluator' do:
[:element |
|
expression = element getAttribute: 'expression'.
om <ObjectMirror> = platformMirror.
es = EvaluatorSubject onModel: (EvaluationViewState onModel: om).
|
es initialSource: expression.
es evaluateLive: expression.
EmbeddedIDEWindow
into: element
openSubject: es].
)
public processAmplets = (
| targetDocument <Document> = Document named: 'dummy' contents: ''. |
domElementsWithClass: 'ampleforth' do: [:element |
|
name <String | Nil> = element getAttribute: 'name'.
expr <String | Nil> = element getAttribute: 'initializer'.
v = mapping at: name ifAbsentPut: [
expr = nil ifFalse: [targetDocument evaluateFragment: expr]
ifTrue: [(StaticLabelFragment text: 'Missing initializer attribute') color: (Color r: 1 g: 0 b: 0)]].
|
element appendChild: v visual
].
)
public processClassPresenters = (
domElementsWithClass: 'classPresenter' do: [:element |
|
errorBlock =
[:errorMessage <String> |
^EmbeddedHopscotchWindow
into: element
openSubject: (ErrorSubject onModel: errorMessage)].
className <String> = element getAttribute: 'className'.
klass <Class>
cm <ClassDeclarationMirror>
|
klass:: namespace at: className ifAbsent: [nil].
klass isKindOfBehavior ifFalse: [errorBlock value: className, ' is not a class'].
(* isKindOfClass should be defined but isn't. *)
cm:: (ClassMirror reflecting: klass) mixin declaration.
EmbeddedIDEWindow
into: element
openSubject: (ClassSubject onDeclaration: cm)
].
)
public processMinibrowsers = (
domElementsWithClass: 'minibrowser' do:
[:element |
EmbeddedIDEWindow
into: element
openSubject: HomeSubject new].
)
public start = (
processAmplets.
processEvaluators.
processMinibrowsers.
processClassPresenters.
)
) : (
)