@gridland/web 0.2.15 → 0.2.17

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 (42) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/index.js +70 -13
  3. package/dist/index.js.map +2 -2
  4. package/dist/{next-CxYMg6AG.d.ts → next-BWTklBmN.d.ts} +22 -3
  5. package/dist/next.d.ts +1 -1
  6. package/dist/next.js +70 -13
  7. package/dist/next.js.map +2 -2
  8. package/dist/vite-plugin.js +73 -38
  9. package/dist/vite-plugin.js.map +1 -1
  10. package/package.json +7 -2
  11. package/src/browser-buffer.ts +715 -0
  12. package/src/core-shims/index.ts +269 -0
  13. package/src/core-shims/renderable-types.ts +4 -0
  14. package/src/core-shims/rgba.ts +195 -0
  15. package/src/core-shims/types.ts +132 -0
  16. package/src/shims/bun-ffi-structs.ts +20 -0
  17. package/src/shims/bun-ffi.ts +28 -0
  18. package/src/shims/console-stub.ts +13 -0
  19. package/src/shims/console.ts +3 -0
  20. package/src/shims/devtools-polyfill-stub.ts +3 -0
  21. package/src/shims/edit-buffer-stub.ts +475 -0
  22. package/src/shims/editor-view-stub.ts +388 -0
  23. package/src/shims/events-shim.ts +81 -0
  24. package/src/shims/filters-stub.ts +4 -0
  25. package/src/shims/hast-stub.ts +8 -0
  26. package/src/shims/native-span-feed-stub.ts +7 -0
  27. package/src/shims/node-buffer.ts +39 -0
  28. package/src/shims/node-fs.ts +20 -0
  29. package/src/shims/node-os.ts +6 -0
  30. package/src/shims/node-path.ts +35 -0
  31. package/src/shims/node-stream.ts +10 -0
  32. package/src/shims/node-url.ts +8 -0
  33. package/src/shims/node-util.ts +33 -0
  34. package/src/shims/renderer-stub.ts +21 -0
  35. package/src/shims/slider-deps.ts +8 -0
  36. package/src/shims/syntax-style-shim.ts +23 -0
  37. package/src/shims/text-buffer-shim.ts +3 -0
  38. package/src/shims/text-buffer-view-shim.ts +2 -0
  39. package/src/shims/timeline-stub.ts +43 -0
  40. package/src/shims/tree-sitter-stub.ts +47 -0
  41. package/src/shims/tree-sitter-styled-text-stub.ts +8 -0
  42. package/src/shims/zig-stub.ts +20 -0
@@ -0,0 +1,475 @@
1
+ // Pure-JS EditBuffer implementation for browser environment.
2
+ // Replaces the native Zig-backed EditBuffer with a simple array-of-lines model.
3
+
4
+ import { EventEmitter } from "events"
5
+
6
+ export interface LogicalCursor {
7
+ row: number
8
+ col: number
9
+ offset: number
10
+ }
11
+
12
+ let nextId = 1
13
+
14
+ export class EditBuffer extends EventEmitter {
15
+ public readonly id: number
16
+ public readonly ptr: number = 0 // dummy pointer
17
+
18
+ private lines: string[] = [""]
19
+ private cursorRow: number = 0
20
+ private cursorCol: number = 0
21
+ private _destroyed: boolean = false
22
+
23
+ private undoStack: { lines: string[]; row: number; col: number }[] = []
24
+ private redoStack: { lines: string[]; row: number; col: number }[] = []
25
+
26
+ private _defaultFg: any = null
27
+ private _defaultBg: any = null
28
+ private _defaultAttributes: number | null = null
29
+ private _syntaxStyle: any = null
30
+ private _highlights: Map<number, any[]> = new Map()
31
+
32
+ constructor() {
33
+ super()
34
+ this.id = nextId++
35
+ }
36
+
37
+ static create(_widthMethod?: any): EditBuffer {
38
+ return new EditBuffer()
39
+ }
40
+
41
+ // --- Text operations ---
42
+
43
+ setText(text: string): void {
44
+ this.lines = text.split("\n")
45
+ if (this.lines.length === 0) this.lines = [""]
46
+ this.cursorRow = 0
47
+ this.cursorCol = 0
48
+ this.undoStack = []
49
+ this.redoStack = []
50
+ this.emit("content-changed")
51
+ this.emit("cursor-changed")
52
+ }
53
+
54
+ setTextOwned(text: string): void {
55
+ this.setText(text)
56
+ }
57
+
58
+ replaceText(text: string): void {
59
+ this.pushUndo()
60
+ this.lines = text.split("\n")
61
+ if (this.lines.length === 0) this.lines = [""]
62
+ this.cursorRow = 0
63
+ this.cursorCol = 0
64
+ this.emit("content-changed")
65
+ this.emit("cursor-changed")
66
+ }
67
+
68
+ replaceTextOwned(text: string): void {
69
+ this.replaceText(text)
70
+ }
71
+
72
+ getText(): string {
73
+ return this.lines.join("\n")
74
+ }
75
+
76
+ getTextRange(startOffset: number, endOffset: number): string {
77
+ const text = this.getText()
78
+ return text.substring(startOffset, endOffset)
79
+ }
80
+
81
+ getTextRangeByCoords(startRow: number, startCol: number, endRow: number, endCol: number): string {
82
+ const startOff = this.positionToOffset(startRow, startCol)
83
+ const endOff = this.positionToOffset(endRow, endCol)
84
+ return this.getText().substring(startOff, endOff)
85
+ }
86
+
87
+ getLineCount(): number {
88
+ return this.lines.length
89
+ }
90
+
91
+ // --- Insert / Delete ---
92
+
93
+ insertChar(char: string): void {
94
+ this.pushUndo()
95
+ const line = this.lines[this.cursorRow]
96
+ this.lines[this.cursorRow] = line.slice(0, this.cursorCol) + char + line.slice(this.cursorCol)
97
+ this.cursorCol += char.length
98
+ this.emit("content-changed")
99
+ this.emit("cursor-changed")
100
+ }
101
+
102
+ insertText(text: string): void {
103
+ this.pushUndo()
104
+ const textLines = text.split("\n")
105
+ const line = this.lines[this.cursorRow]
106
+ const before = line.slice(0, this.cursorCol)
107
+ const after = line.slice(this.cursorCol)
108
+
109
+ if (textLines.length === 1) {
110
+ this.lines[this.cursorRow] = before + textLines[0] + after
111
+ this.cursorCol += textLines[0].length
112
+ } else {
113
+ this.lines[this.cursorRow] = before + textLines[0]
114
+ const newLines = textLines.slice(1, -1)
115
+ const lastLine = textLines[textLines.length - 1] + after
116
+ this.lines.splice(this.cursorRow + 1, 0, ...newLines, lastLine)
117
+ this.cursorRow += textLines.length - 1
118
+ this.cursorCol = textLines[textLines.length - 1].length
119
+ }
120
+ this.emit("content-changed")
121
+ this.emit("cursor-changed")
122
+ }
123
+
124
+ deleteChar(): void {
125
+ this.pushUndo()
126
+ const line = this.lines[this.cursorRow]
127
+ if (this.cursorCol < line.length) {
128
+ this.lines[this.cursorRow] = line.slice(0, this.cursorCol) + line.slice(this.cursorCol + 1)
129
+ this.emit("content-changed")
130
+ } else if (this.cursorRow < this.lines.length - 1) {
131
+ // Join with next line
132
+ this.lines[this.cursorRow] = line + this.lines[this.cursorRow + 1]
133
+ this.lines.splice(this.cursorRow + 1, 1)
134
+ this.emit("content-changed")
135
+ }
136
+ }
137
+
138
+ deleteCharBackward(): void {
139
+ this.pushUndo()
140
+ if (this.cursorCol > 0) {
141
+ const line = this.lines[this.cursorRow]
142
+ this.lines[this.cursorRow] = line.slice(0, this.cursorCol - 1) + line.slice(this.cursorCol)
143
+ this.cursorCol--
144
+ this.emit("content-changed")
145
+ this.emit("cursor-changed")
146
+ } else if (this.cursorRow > 0) {
147
+ // Join with previous line
148
+ const prevLine = this.lines[this.cursorRow - 1]
149
+ this.cursorCol = prevLine.length
150
+ this.lines[this.cursorRow - 1] = prevLine + this.lines[this.cursorRow]
151
+ this.lines.splice(this.cursorRow, 1)
152
+ this.cursorRow--
153
+ this.emit("content-changed")
154
+ this.emit("cursor-changed")
155
+ }
156
+ }
157
+
158
+ newLine(): void {
159
+ this.pushUndo()
160
+ const line = this.lines[this.cursorRow]
161
+ const before = line.slice(0, this.cursorCol)
162
+ const after = line.slice(this.cursorCol)
163
+ this.lines[this.cursorRow] = before
164
+ this.lines.splice(this.cursorRow + 1, 0, after)
165
+ this.cursorRow++
166
+ this.cursorCol = 0
167
+ this.emit("content-changed")
168
+ this.emit("cursor-changed")
169
+ }
170
+
171
+ deleteLine(): void {
172
+ this.pushUndo()
173
+ if (this.lines.length === 1) {
174
+ this.lines[0] = ""
175
+ this.cursorCol = 0
176
+ } else {
177
+ this.lines.splice(this.cursorRow, 1)
178
+ if (this.cursorRow >= this.lines.length) {
179
+ this.cursorRow = this.lines.length - 1
180
+ }
181
+ this.cursorCol = Math.min(this.cursorCol, this.lines[this.cursorRow].length)
182
+ }
183
+ this.emit("content-changed")
184
+ this.emit("cursor-changed")
185
+ }
186
+
187
+ deleteRange(startLine: number, startCol: number, endLine: number, endCol: number): void {
188
+ this.pushUndo()
189
+ const startOff = this.positionToOffset(startLine, startCol)
190
+ const endOff = this.positionToOffset(endLine, endCol)
191
+ const text = this.getText()
192
+ const newText = text.substring(0, startOff) + text.substring(endOff)
193
+ this.lines = newText.split("\n")
194
+ if (this.lines.length === 0) this.lines = [""]
195
+ this.cursorRow = startLine
196
+ this.cursorCol = startCol
197
+ this.clampCursor()
198
+ this.emit("content-changed")
199
+ this.emit("cursor-changed")
200
+ }
201
+
202
+ clear(): void {
203
+ this.pushUndo()
204
+ this.lines = [""]
205
+ this.cursorRow = 0
206
+ this.cursorCol = 0
207
+ this.emit("content-changed")
208
+ this.emit("cursor-changed")
209
+ }
210
+
211
+ // --- Cursor ---
212
+
213
+ setCursor(line: number, col: number): void {
214
+ this.cursorRow = line
215
+ this.cursorCol = col
216
+ this.clampCursor()
217
+ this.emit("cursor-changed")
218
+ }
219
+
220
+ setCursorToLineCol(line: number, col: number): void {
221
+ this.setCursor(line, col)
222
+ }
223
+
224
+ getCursorPosition(): LogicalCursor {
225
+ return {
226
+ row: this.cursorRow,
227
+ col: this.cursorCol,
228
+ offset: this.positionToOffset(this.cursorRow, this.cursorCol),
229
+ }
230
+ }
231
+
232
+ setCursorByOffset(offset: number): void {
233
+ const pos = this.offsetToPosition(offset)
234
+ if (pos) {
235
+ this.cursorRow = pos.row
236
+ this.cursorCol = pos.col
237
+ this.emit("cursor-changed")
238
+ }
239
+ }
240
+
241
+ moveCursorLeft(): void {
242
+ if (this.cursorCol > 0) {
243
+ this.cursorCol--
244
+ } else if (this.cursorRow > 0) {
245
+ this.cursorRow--
246
+ this.cursorCol = this.lines[this.cursorRow].length
247
+ }
248
+ this.emit("cursor-changed")
249
+ }
250
+
251
+ moveCursorRight(): void {
252
+ const line = this.lines[this.cursorRow]
253
+ if (this.cursorCol < line.length) {
254
+ this.cursorCol++
255
+ } else if (this.cursorRow < this.lines.length - 1) {
256
+ this.cursorRow++
257
+ this.cursorCol = 0
258
+ }
259
+ this.emit("cursor-changed")
260
+ }
261
+
262
+ moveCursorUp(): void {
263
+ if (this.cursorRow > 0) {
264
+ this.cursorRow--
265
+ this.cursorCol = Math.min(this.cursorCol, this.lines[this.cursorRow].length)
266
+ this.emit("cursor-changed")
267
+ }
268
+ }
269
+
270
+ moveCursorDown(): void {
271
+ if (this.cursorRow < this.lines.length - 1) {
272
+ this.cursorRow++
273
+ this.cursorCol = Math.min(this.cursorCol, this.lines[this.cursorRow].length)
274
+ this.emit("cursor-changed")
275
+ }
276
+ }
277
+
278
+ gotoLine(line: number): void {
279
+ this.cursorRow = Math.max(0, Math.min(line, this.lines.length - 1))
280
+ this.cursorCol = Math.min(this.cursorCol, this.lines[this.cursorRow].length)
281
+ this.emit("cursor-changed")
282
+ }
283
+
284
+ getEOL(): LogicalCursor {
285
+ const col = this.lines[this.cursorRow].length
286
+ return {
287
+ row: this.cursorRow,
288
+ col,
289
+ offset: this.positionToOffset(this.cursorRow, col),
290
+ }
291
+ }
292
+
293
+ getNextWordBoundary(): LogicalCursor {
294
+ const text = this.getText()
295
+ const offset = this.positionToOffset(this.cursorRow, this.cursorCol)
296
+ let i = offset
297
+ // Skip current word chars
298
+ while (i < text.length && /\w/.test(text[i])) i++
299
+ // Skip non-word chars
300
+ while (i < text.length && !/\w/.test(text[i])) i++
301
+ const pos = this.offsetToPosition(i)!
302
+ return { row: pos.row, col: pos.col, offset: i }
303
+ }
304
+
305
+ getPrevWordBoundary(): LogicalCursor {
306
+ const text = this.getText()
307
+ let i = this.positionToOffset(this.cursorRow, this.cursorCol)
308
+ if (i > 0) i--
309
+ // Skip non-word chars
310
+ while (i > 0 && !/\w/.test(text[i])) i--
311
+ // Skip word chars
312
+ while (i > 0 && /\w/.test(text[i - 1])) i--
313
+ const pos = this.offsetToPosition(i)!
314
+ return { row: pos.row, col: pos.col, offset: i }
315
+ }
316
+
317
+ // --- Offset / Position conversion ---
318
+
319
+ positionToOffset(row: number, col: number): number {
320
+ let offset = 0
321
+ for (let r = 0; r < row && r < this.lines.length; r++) {
322
+ offset += this.lines[r].length + 1 // +1 for \n
323
+ }
324
+ offset += Math.min(col, row < this.lines.length ? this.lines[row].length : 0)
325
+ return offset
326
+ }
327
+
328
+ offsetToPosition(offset: number): { row: number; col: number } | null {
329
+ let remaining = offset
330
+ for (let r = 0; r < this.lines.length; r++) {
331
+ if (remaining <= this.lines[r].length) {
332
+ return { row: r, col: remaining }
333
+ }
334
+ remaining -= this.lines[r].length + 1
335
+ }
336
+ // Clamp to end
337
+ const lastRow = this.lines.length - 1
338
+ return { row: lastRow, col: this.lines[lastRow].length }
339
+ }
340
+
341
+ getLineStartOffset(row: number): number {
342
+ return this.positionToOffset(row, 0)
343
+ }
344
+
345
+ // --- Undo / Redo ---
346
+
347
+ private pushUndo(): void {
348
+ this.undoStack.push({
349
+ lines: [...this.lines],
350
+ row: this.cursorRow,
351
+ col: this.cursorCol,
352
+ })
353
+ this.redoStack = []
354
+ // Limit undo history
355
+ if (this.undoStack.length > 100) this.undoStack.shift()
356
+ }
357
+
358
+ undo(): string | null {
359
+ const state = this.undoStack.pop()
360
+ if (!state) return null
361
+ this.redoStack.push({
362
+ lines: [...this.lines],
363
+ row: this.cursorRow,
364
+ col: this.cursorCol,
365
+ })
366
+ this.lines = state.lines
367
+ this.cursorRow = state.row
368
+ this.cursorCol = state.col
369
+ this.emit("content-changed")
370
+ this.emit("cursor-changed")
371
+ return this.getText()
372
+ }
373
+
374
+ redo(): string | null {
375
+ const state = this.redoStack.pop()
376
+ if (!state) return null
377
+ this.undoStack.push({
378
+ lines: [...this.lines],
379
+ row: this.cursorRow,
380
+ col: this.cursorCol,
381
+ })
382
+ this.lines = state.lines
383
+ this.cursorRow = state.row
384
+ this.cursorCol = state.col
385
+ this.emit("content-changed")
386
+ this.emit("cursor-changed")
387
+ return this.getText()
388
+ }
389
+
390
+ canUndo(): boolean {
391
+ return this.undoStack.length > 0
392
+ }
393
+
394
+ canRedo(): boolean {
395
+ return this.redoStack.length > 0
396
+ }
397
+
398
+ clearHistory(): void {
399
+ this.undoStack = []
400
+ this.redoStack = []
401
+ }
402
+
403
+ // --- Styling (no-ops for browser, but store values) ---
404
+
405
+ setDefaultFg(fg: any): void {
406
+ this._defaultFg = fg
407
+ }
408
+ setDefaultBg(bg: any): void {
409
+ this._defaultBg = bg
410
+ }
411
+ setDefaultAttributes(attributes: number | null): void {
412
+ this._defaultAttributes = attributes
413
+ }
414
+ resetDefaults(): void {
415
+ this._defaultFg = null
416
+ this._defaultBg = null
417
+ this._defaultAttributes = null
418
+ }
419
+ setSyntaxStyle(style: any): void {
420
+ this._syntaxStyle = style
421
+ }
422
+ getSyntaxStyle(): any {
423
+ return this._syntaxStyle ?? null
424
+ }
425
+
426
+ // --- Highlights (store but don't render natively) ---
427
+
428
+ addHighlight(lineIdx: number, highlight: any): void {
429
+ if (!this._highlights.has(lineIdx)) this._highlights.set(lineIdx, [])
430
+ this._highlights.get(lineIdx)!.push(highlight)
431
+ }
432
+ addHighlightByCharRange(highlight: any): void {
433
+ // Store globally
434
+ if (!this._highlights.has(-1)) this._highlights.set(-1, [])
435
+ this._highlights.get(-1)!.push(highlight)
436
+ }
437
+ removeHighlightsByRef(hlRef: number): void {
438
+ for (const [key, highlights] of this._highlights) {
439
+ this._highlights.set(
440
+ key,
441
+ highlights.filter((h: any) => h.ref !== hlRef),
442
+ )
443
+ }
444
+ }
445
+ clearLineHighlights(lineIdx: number): void {
446
+ this._highlights.delete(lineIdx)
447
+ }
448
+ clearAllHighlights(): void {
449
+ this._highlights.clear()
450
+ }
451
+ getLineHighlights(lineIdx: number): any[] {
452
+ return this._highlights.get(lineIdx) || []
453
+ }
454
+
455
+ // --- Debug ---
456
+
457
+ debugLogRope(): void {
458
+ console.log("EditBuffer lines:", this.lines)
459
+ }
460
+
461
+ // --- Cleanup ---
462
+
463
+ destroy(): void {
464
+ if (this._destroyed) return
465
+ this._destroyed = true
466
+ this.removeAllListeners()
467
+ }
468
+
469
+ // --- Internal helpers ---
470
+
471
+ private clampCursor(): void {
472
+ this.cursorRow = Math.max(0, Math.min(this.cursorRow, this.lines.length - 1))
473
+ this.cursorCol = Math.max(0, Math.min(this.cursorCol, this.lines[this.cursorRow].length))
474
+ }
475
+ }