Skip to content

Commit 191a7c0

Browse files
committed
Code mirror update
1 parent 2525d68 commit 191a7c0

11 files changed

+90
-109
lines changed

designer/DesignerApp.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,31 @@ class DesignerApp extends AbstractParticleComponentParser {
182182
this._bindParticleComponentFrameworkCommandListenersOnBody()
183183
this.renderAndGetRenderReport(this.willowBrowser.getBodyStumpParticle())
184184

185-
this.parsersInstance = new ParsersCodeMirrorMode("parsers", () => parsersParser, undefined, CodeMirror).register().fromTextAreaWithAutocomplete(document.getElementById("parsersConsole"), { lineWrapping: true })
185+
this.parsersInstance = new ParsersCodeMirrorMode(
186+
"parsers",
187+
() => {
188+
this._parsersDidUpdate()
189+
return this.parsersProgram
190+
},
191+
CodeMirror
192+
)
193+
.register()
194+
.fromTextAreaWithAutocomplete(document.getElementById("parsersConsole"), { lineWrapping: true })
186195

187196
this.parsersInstance.on("keyup", () => {
188197
this._onParsersKeyup()
189198
})
190199

191-
this.codeInstance = new ParsersCodeMirrorMode("custom", () => this._getParsersParser(), undefined, CodeMirror).register().fromTextAreaWithAutocomplete(document.getElementById("codeConsole"), { lineWrapping: true })
200+
this.codeInstance = new ParsersCodeMirrorMode(
201+
"custom",
202+
() => {
203+
this._updateProgram()
204+
return this.program
205+
},
206+
CodeMirror
207+
)
208+
.register()
209+
.fromTextAreaWithAutocomplete(document.getElementById("codeConsole"), { lineWrapping: true })
192210

193211
this.codeInstance.on("keyup", () => this._onCodeKeyUp())
194212

@@ -256,15 +274,17 @@ class DesignerApp extends AbstractParticleComponentParser {
256274
this.willowBrowser.setHtmlOfElementWithIdHack("otherErrorsDiv", err)
257275
}
258276

259-
private _parsersDidUpdate() {
260-
const parsersCode = this.getParsersCode()
277+
_currentParserCode?: string
278+
private _parsersDidUpdate(parsersCode = this.getParsersCode()) {
279+
if (this._currentParserCode === parsersCode) return
261280
this.parsersProgram = new parsersParser(parsersCode)
262281
const errs = this.parsersProgram.getAllErrors().map((err: any) => err.toObject())
263282
this.willowBrowser.setHtmlOfElementWithIdHack("parsersErrorsConsole", errs.length ? new Particle(errs).toFormattedTable(200) : "0 errors")
264283
const parsersProgram = new HandParsersProgram(this.parsersInstance.getValue())
265284
const readme = parsersProgram.toReadMe()
266285

267286
this.willowBrowser.setHtmlOfElementWithIdHack("readmeComponent", readme)
287+
this._currentParserCode = parsersCode
268288
}
269289

270290
private _updateShareLink() {
@@ -281,14 +301,19 @@ class DesignerApp extends AbstractParticleComponentParser {
281301
return "#" + encodeURIComponent(particle.asString)
282302
}
283303

304+
_currentCode?: string
305+
_updateProgram() {
306+
const code = this.getCodeValue()
307+
if (this._currentCode === code) return
308+
const parser = this._getParsersParser()
309+
this.program = new parser(code)
310+
this._currentCode = code
311+
}
284312
_onCodeKeyUp() {
285313
const { willowBrowser } = this
286-
const code = this.getCodeValue()
287314
this._updateLocalStorage()
288-
const parsersParser = this._getParsersParser()
315+
this._updateProgram()
289316
const that = this
290-
291-
this.program = new parsersParser(code)
292317
const errs = this.program.scopeErrors.concat(this.program.getAllErrors())
293318

294319
willowBrowser.setHtmlOfElementWithIdHack("codeErrorsConsole", errs.length ? new Particle(errs.map((err: any) => err.toObject())).toFormattedTable(200) : "0 errors")

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "scrollsdk",
3-
"version": "107.0.0",
3+
"version": "107.0.1",
44
"description": "This npm package includes the Particles class, the Parsers compiler-compiler, a Parsers IDE, and more, all implemented in Particles, Parsers, and TypeScript.",
55
"types": "./built/scrollsdk.node.d.ts",
66
"main": "./products/Particle.js",

parsers/ParsersCodeMirrorMode.test.ts

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,7 @@ testParticles.codeMirrorTest = equal => {
9494
const code = `testParser
9595
root`
9696

97-
const mock = new MockCodeMirror(
98-
() =>
99-
new ParsersCodeMirrorMode(
100-
"parsersParser",
101-
() => ParsersProgram,
102-
() => code
103-
)
104-
)
97+
const mock = new MockCodeMirror(() => new ParsersCodeMirrorMode("parsersParser", () => new ParsersProgram(code)))
10598
const tokenLines = mock.getTokenLines(code)
10699
equal(tokenLines.join(" "), `def bracket atom`)
107100
}
@@ -111,26 +104,12 @@ testParticles.iris = equal => {
111104
const goodCode = `6.1 3 4.9 2 virginica`
112105
const codeWithMissingAtom = `6.1 3 4.9 virginica`
113106
// Act
114-
const tokenLines = new MockCodeMirror(
115-
() =>
116-
new ParsersCodeMirrorMode(
117-
"irisParser",
118-
() => irisParser,
119-
() => goodCode
120-
)
121-
).getTokenLines(goodCode)
107+
const tokenLines = new MockCodeMirror(() => new ParsersCodeMirrorMode("irisParser", () => new irisParser(goodCode))).getTokenLines(goodCode)
122108
// Assert
123109
equal(tokenLines.join(" "), `number bracket number bracket number bracket number bracket atom`)
124110

125111
// Act
126-
const tokenLines2 = new MockCodeMirror(
127-
() =>
128-
new ParsersCodeMirrorMode(
129-
"irisParser",
130-
() => irisParser,
131-
() => codeWithMissingAtom
132-
)
133-
).getTokenLines(codeWithMissingAtom)
112+
const tokenLines2 = new MockCodeMirror(() => new ParsersCodeMirrorMode("irisParser", () => new irisParser(codeWithMissingAtom))).getTokenLines(codeWithMissingAtom)
134113
// Assert
135114
equal(tokenLines2.join(" "), `number bracket number bracket number bracket bracket atom`)
136115
}
@@ -140,14 +119,7 @@ testParticles.codeMirrorTest2 = equal => {
140119
root
141120
foobarParser`
142121

143-
const mock = new MockCodeMirror(
144-
() =>
145-
new ParsersCodeMirrorMode(
146-
"parsersParser",
147-
() => ParsersProgram,
148-
() => code
149-
)
150-
)
122+
const mock = new MockCodeMirror(() => new ParsersCodeMirrorMode("parsersParser", () => new ParsersProgram(code)))
151123
const tokenLines = mock.getTokenLines(code)
152124
equal(tokenLines.length, 3)
153125
equal(tokenLines.join(" "), `def bracket atom def`)
@@ -156,14 +128,7 @@ foobarParser`
156128
testParticles.regressionTest = equal => {
157129
const code = Disk.read(__dirname + "/ParsersCodeMirrorMode.regression.stamp")
158130

159-
const mock = new MockCodeMirror(
160-
() =>
161-
new ParsersCodeMirrorMode(
162-
"stampParser",
163-
() => stamp,
164-
() => code
165-
)
166-
)
131+
const mock = new MockCodeMirror(() => new ParsersCodeMirrorMode("stampParser", () => new stamp(code)))
167132
const tokenLines = mock.getTokenLines(code)
168133
equal(tokenLines.length, 217)
169134
}
@@ -173,14 +138,7 @@ testParticles.regression2 = equal => {
173138
prettier
174139
object`
175140

176-
const mock = new MockCodeMirror(
177-
() =>
178-
new ParsersCodeMirrorMode(
179-
"dugParser",
180-
() => DugProgram,
181-
() => code
182-
)
183-
)
141+
const mock = new MockCodeMirror(() => new ParsersCodeMirrorMode("dugParser", () => new DugProgram(code)))
184142
const tokenLines = mock.getTokenLines(code)
185143
equal(tokenLines.length, 3)
186144
equal(tokenLines.join(" "), `keyword bracket string bracket bracket keyword`)

parsers/ParsersCodeMirrorMode.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -197,31 +197,17 @@ interface particleCodeMirrorState {
197197
}
198198

199199
class ParsersCodeMirrorMode {
200-
constructor(name: string, getRootParserFn: () => particlesTypes.ParticleProgramParser, getProgramCodeFn: (instance: CodeMirrorLib.EditorFromTextArea) => string, codeMirrorLib: typeof CodeMirrorLib = undefined) {
200+
constructor(name: string, getParsedProgramFn: () => particlesTypes.particleProgram, codeMirrorLib: typeof CodeMirrorLib = undefined) {
201201
this._name = name
202-
this._getRootParserFn = getRootParserFn
203-
this._getProgramCodeFn = getProgramCodeFn || (instance => (instance ? <string>instance.getValue() : this._originalValue))
202+
this._getParsedProgram = getParsedProgramFn
204203
this._codeMirrorLib = codeMirrorLib
205204
}
206205

207206
private _name: string
208-
private _getProgramCodeFn: (cmInstance: CodeMirrorLib.EditorFromTextArea) => string
209-
private _getRootParserFn: () => particlesTypes.ParticleProgramParser
210207
private _codeMirrorLib: typeof CodeMirrorLib
211-
private _cachedSource: string
212-
private _cachedProgram: particlesTypes.particleProgram
213208
private _cmInstance: CodeMirrorLib.EditorFromTextArea
214209
private _originalValue: string
215210

216-
_getParsedProgram() {
217-
const source = this._getProgramCodeFn(this._cmInstance) || ""
218-
if (!this._cachedProgram || this._cachedSource !== source) {
219-
this._cachedSource = source
220-
this._cachedProgram = new (<any>this._getRootParserFn())(source)
221-
}
222-
return this._cachedProgram
223-
}
224-
225211
private _getExcludedIntelliSenseTriggerKeys(): particlesTypes.stringMap {
226212
return {
227213
"8": "backspace",
@@ -304,7 +290,8 @@ class ParsersCodeMirrorMode {
304290
async codeMirrorAutocomplete(cmInstance: CodeMirrorLib.EditorFromTextArea, options: any) {
305291
const cursor = cmInstance.getDoc().getCursor()
306292
const codeMirrorLib = this._getCodeMirrorLib()
307-
const result = await this._getParsedProgram().getAutocompleteResultsAt(cursor.line, cursor.ch)
293+
const program = this._getParsedProgram()
294+
const result = await program.getAutocompleteResultsAt(cursor.line, cursor.ch)
308295

309296
// It seems to be better UX if there's only 1 result, and its the atom the user entered, to close autocomplete
310297
if (result.matches.length === 1 && result.matches[0].text === result.atom) return null

particle/Particle.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3303,7 +3303,7 @@ class Particle extends AbstractParticle {
33033303
return str ? indent + str.replace(/\n/g, indent) : ""
33043304
}
33053305

3306-
static getVersion = () => "107.0.0"
3306+
static getVersion = () => "107.0.1"
33073307

33083308
static fromDisk(path: string): Particle {
33093309
const format = this._getFileFormat(path)

products/DesignerApp.browser.js

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,29 @@ class DesignerApp extends AbstractParticleComponentParser {
138138
async start() {
139139
this._bindParticleComponentFrameworkCommandListenersOnBody()
140140
this.renderAndGetRenderReport(this.willowBrowser.getBodyStumpParticle())
141-
this.parsersInstance = new ParsersCodeMirrorMode("parsers", () => parsersParser, undefined, CodeMirror).register().fromTextAreaWithAutocomplete(document.getElementById("parsersConsole"), { lineWrapping: true })
141+
this.parsersInstance = new ParsersCodeMirrorMode(
142+
"parsers",
143+
() => {
144+
this._parsersDidUpdate()
145+
return this.parsersProgram
146+
},
147+
CodeMirror
148+
)
149+
.register()
150+
.fromTextAreaWithAutocomplete(document.getElementById("parsersConsole"), { lineWrapping: true })
142151
this.parsersInstance.on("keyup", () => {
143152
this._onParsersKeyup()
144153
})
145-
this.codeInstance = new ParsersCodeMirrorMode("custom", () => this._getParsersParser(), undefined, CodeMirror).register().fromTextAreaWithAutocomplete(document.getElementById("codeConsole"), { lineWrapping: true })
154+
this.codeInstance = new ParsersCodeMirrorMode(
155+
"custom",
156+
() => {
157+
this._updateProgram()
158+
return this.program
159+
},
160+
CodeMirror
161+
)
162+
.register()
163+
.fromTextAreaWithAutocomplete(document.getElementById("codeConsole"), { lineWrapping: true })
146164
this.codeInstance.on("keyup", () => this._onCodeKeyUp())
147165
// loadFromURL
148166
const wasLoadedFromDeepLink = await this._loadFromDeepLink()
@@ -195,14 +213,15 @@ class DesignerApp extends AbstractParticleComponentParser {
195213
console.log(err)
196214
this.willowBrowser.setHtmlOfElementWithIdHack("otherErrorsDiv", err)
197215
}
198-
_parsersDidUpdate() {
199-
const parsersCode = this.getParsersCode()
216+
_parsersDidUpdate(parsersCode = this.getParsersCode()) {
217+
if (this._currentParserCode === parsersCode) return
200218
this.parsersProgram = new parsersParser(parsersCode)
201219
const errs = this.parsersProgram.getAllErrors().map(err => err.toObject())
202220
this.willowBrowser.setHtmlOfElementWithIdHack("parsersErrorsConsole", errs.length ? new Particle(errs).toFormattedTable(200) : "0 errors")
203221
const parsersProgram = new HandParsersProgram(this.parsersInstance.getValue())
204222
const readme = parsersProgram.toReadMe()
205223
this.willowBrowser.setHtmlOfElementWithIdHack("readmeComponent", readme)
224+
this._currentParserCode = parsersCode
206225
}
207226
_updateShareLink() {
208227
const url = new URL(location.href)
@@ -216,13 +235,18 @@ class DesignerApp extends AbstractParticleComponentParser {
216235
particle.appendLineAndSubparticles("sample", this.getCodeValue())
217236
return "#" + encodeURIComponent(particle.asString)
218237
}
238+
_updateProgram() {
239+
const code = this.getCodeValue()
240+
if (this._currentCode === code) return
241+
const parser = this._getParsersParser()
242+
this.program = new parser(code)
243+
this._currentCode = code
244+
}
219245
_onCodeKeyUp() {
220246
const { willowBrowser } = this
221-
const code = this.getCodeValue()
222247
this._updateLocalStorage()
223-
const parsersParser = this._getParsersParser()
248+
this._updateProgram()
224249
const that = this
225-
this.program = new parsersParser(code)
226250
const errs = this.program.scopeErrors.concat(this.program.getAllErrors())
227251
willowBrowser.setHtmlOfElementWithIdHack("codeErrorsConsole", errs.length ? new Particle(errs.map(err => err.toObject())).toFormattedTable(200) : "0 errors")
228252
const cursor = this.codeInstance.getCursor()

products/ParsersCodeMirrorMode.browser.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -180,20 +180,11 @@ const textMateScopeToCodeMirrorStyle = (scopeSegments, style = tmToCm) => {
180180
return matchingBranch ? textMateScopeToCodeMirrorStyle(scopeSegments, matchingBranch) || matchingBranch.$ || null : null
181181
}
182182
class ParsersCodeMirrorMode {
183-
constructor(name, getRootParserFn, getProgramCodeFn, codeMirrorLib = undefined) {
183+
constructor(name, getParsedProgramFn, codeMirrorLib = undefined) {
184184
this._name = name
185-
this._getRootParserFn = getRootParserFn
186-
this._getProgramCodeFn = getProgramCodeFn || (instance => (instance ? instance.getValue() : this._originalValue))
185+
this._getParsedProgram = getParsedProgramFn
187186
this._codeMirrorLib = codeMirrorLib
188187
}
189-
_getParsedProgram() {
190-
const source = this._getProgramCodeFn(this._cmInstance) || ""
191-
if (!this._cachedProgram || this._cachedSource !== source) {
192-
this._cachedSource = source
193-
this._cachedProgram = new (this._getRootParserFn())(source)
194-
}
195-
return this._cachedProgram
196-
}
197188
_getExcludedIntelliSenseTriggerKeys() {
198189
return {
199190
8: "backspace",
@@ -269,7 +260,8 @@ class ParsersCodeMirrorMode {
269260
async codeMirrorAutocomplete(cmInstance, options) {
270261
const cursor = cmInstance.getDoc().getCursor()
271262
const codeMirrorLib = this._getCodeMirrorLib()
272-
const result = await this._getParsedProgram().getAutocompleteResultsAt(cursor.line, cursor.ch)
263+
const program = this._getParsedProgram()
264+
const result = await program.getAutocompleteResultsAt(cursor.line, cursor.ch)
273265
// It seems to be better UX if there's only 1 result, and its the atom the user entered, to close autocomplete
274266
if (result.matches.length === 1 && result.matches[0].text === result.atom) return null
275267
return result.matches.length

products/ParsersCodeMirrorMode.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,20 +181,11 @@ const textMateScopeToCodeMirrorStyle = (scopeSegments, style = tmToCm) => {
181181
return matchingBranch ? textMateScopeToCodeMirrorStyle(scopeSegments, matchingBranch) || matchingBranch.$ || null : null
182182
}
183183
class ParsersCodeMirrorMode {
184-
constructor(name, getRootParserFn, getProgramCodeFn, codeMirrorLib = undefined) {
184+
constructor(name, getParsedProgramFn, codeMirrorLib = undefined) {
185185
this._name = name
186-
this._getRootParserFn = getRootParserFn
187-
this._getProgramCodeFn = getProgramCodeFn || (instance => (instance ? instance.getValue() : this._originalValue))
186+
this._getParsedProgram = getParsedProgramFn
188187
this._codeMirrorLib = codeMirrorLib
189188
}
190-
_getParsedProgram() {
191-
const source = this._getProgramCodeFn(this._cmInstance) || ""
192-
if (!this._cachedProgram || this._cachedSource !== source) {
193-
this._cachedSource = source
194-
this._cachedProgram = new (this._getRootParserFn())(source)
195-
}
196-
return this._cachedProgram
197-
}
198189
_getExcludedIntelliSenseTriggerKeys() {
199190
return {
200191
8: "backspace",
@@ -270,7 +261,8 @@ class ParsersCodeMirrorMode {
270261
async codeMirrorAutocomplete(cmInstance, options) {
271262
const cursor = cmInstance.getDoc().getCursor()
272263
const codeMirrorLib = this._getCodeMirrorLib()
273-
const result = await this._getParsedProgram().getAutocompleteResultsAt(cursor.line, cursor.ch)
264+
const program = this._getParsedProgram()
265+
const result = await program.getAutocompleteResultsAt(cursor.line, cursor.ch)
274266
// It seems to be better UX if there's only 1 result, and its the atom the user entered, to close autocomplete
275267
if (result.matches.length === 1 && result.matches[0].text === result.atom) return null
276268
return result.matches.length

products/Particle.browser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2823,7 +2823,7 @@ Particle.iris = `sepal_length,sepal_width,petal_length,petal_width,species
28232823
4.9,2.5,4.5,1.7,virginica
28242824
5.1,3.5,1.4,0.2,setosa
28252825
5,3.4,1.5,0.2,setosa`
2826-
Particle.getVersion = () => "107.0.0"
2826+
Particle.getVersion = () => "107.0.1"
28272827
class AbstractExtendibleParticle extends Particle {
28282828
_getFromExtended(cuePath) {
28292829
const hit = this._getParticleFromExtended(cuePath)

products/Particle.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2814,7 +2814,7 @@ Particle.iris = `sepal_length,sepal_width,petal_length,petal_width,species
28142814
4.9,2.5,4.5,1.7,virginica
28152815
5.1,3.5,1.4,0.2,setosa
28162816
5,3.4,1.5,0.2,setosa`
2817-
Particle.getVersion = () => "107.0.0"
2817+
Particle.getVersion = () => "107.0.1"
28182818
class AbstractExtendibleParticle extends Particle {
28192819
_getFromExtended(cuePath) {
28202820
const hit = this._getParticleFromExtended(cuePath)

releaseNotes.scroll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ node_modules/scroll-cli/microlangs/changes.parsers
2020

2121
thinColumns 4
2222

23-
📦 107.0.0 2025-04-06
23+
📦 107.0.1 2025-04-09
24+
🏥 updated ParsersCodeMirrorMode API to allow for multiple parsers.
25+
26+
📦 107.0.0 2025-04-08
2427

2528
This is a major release that moves Scroll from a multi-pass parser to a single pass parser.
2629

0 commit comments

Comments
 (0)