tangled
alpha
login
or
join now
nonbinary.computer
/
weaver
atproto blogging
24
fork
atom
overview
issues
2
pulls
pipelines
debug logs demotion
Orual
1 month ago
4c9f8b6f
55d185bc
+228
-21
2 changed files
expand all
collapse all
unified
split
crates
weaver-editor-browser
src
dom_sync.rs
docs
graph-data.json
+19
-21
crates/weaver-editor-browser/src/dom_sync.rs
···
99
99
let anchor_offset = selection.anchor_offset() as usize;
100
100
let focus_offset = selection.focus_offset() as usize;
101
101
102
102
-
tracing::debug!(
102
102
+
tracing::trace!(
103
103
anchor_node_name = %anchor_node.node_name(),
104
104
anchor_offset,
105
105
focus_node_name = %focus_node.node_name(),
···
166
166
.text_content()
167
167
.map(|s| s.chars().take(20).collect::<String>())
168
168
.unwrap_or_default();
169
169
-
tracing::debug!(
169
169
+
tracing::trace!(
170
170
node_name = %node_name,
171
171
node_id_attr = ?node_id_attr,
172
172
text_preview = %text_content_preview.escape_debug(),
···
180
180
// offset_in_text_node is the offset within that descendant, NOT the
181
181
// child index in the editor.
182
182
if let Some(ref walked_node) = walked_from {
183
183
-
tracing::debug!(
183
183
+
tracing::trace!(
184
184
walked_from_node_name = %walked_node.node_name(),
185
185
"dom_position_to_text_offset: walked up to editor from descendant"
186
186
);
···
208
208
209
209
// Selection is directly on the editor container (e.g., Cmd+A).
210
210
let child_count = editor_element.child_element_count() as usize;
211
211
-
tracing::debug!(
211
211
+
tracing::trace!(
212
212
offset_in_text_node,
213
213
child_count,
214
214
"dom_position_to_text_offset: selection directly on editor container"
215
215
);
216
216
if offset_in_text_node == 0 {
217
217
-
tracing::debug!(
217
217
+
tracing::trace!(
218
218
"dom_position_to_text_offset: returning 0 (editor container offset 0)"
219
219
);
220
220
return Some(0);
221
221
} else if offset_in_text_node >= child_count {
222
222
let end = paragraphs.last().map(|p| p.char_range.end);
223
223
-
tracing::debug!(end = ?end, "dom_position_to_text_offset: returning end of last paragraph");
223
223
+
tracing::trace!(end = ?end, "dom_position_to_text_offset: returning end of last paragraph");
224
224
return end;
225
225
}
226
226
break None;
···
233
233
if let Some(id) = id {
234
234
// Match both old-style "n0" and paragraph-prefixed "p-2-n0" node IDs.
235
235
let is_node_id = id.starts_with('n') || id.contains("-n");
236
236
-
tracing::debug!(
236
236
+
tracing::trace!(
237
237
id = %id,
238
238
is_node_id,
239
239
-
starts_with_n = id.starts_with('n'),
240
240
-
contains_dash_n = id.contains("-n"),
241
239
"dom_position_to_text_offset: checking ID pattern"
242
240
);
243
241
if is_node_id {
···
253
251
let node_id = match node_id {
254
252
Some(id) => id,
255
253
None => {
256
256
-
tracing::debug!("dom_position_to_text_offset: no node_id found in walk-up");
254
254
+
tracing::trace!("dom_position_to_text_offset: no node_id found in walk-up");
257
255
return None;
258
256
}
259
257
};
260
258
261
261
-
tracing::debug!(node_id = %node_id, "dom_position_to_text_offset: found node_id");
259
259
+
tracing::trace!(node_id = %node_id, "dom_position_to_text_offset: found node_id");
262
260
263
261
let container = dom_document.get_element_by_id(&node_id).or_else(|| {
264
262
let selector = format!("[data-node-id='{}']", node_id);
···
288
286
}
289
287
utf16_offset_in_container = text_counted;
290
288
291
291
-
tracing::debug!(
289
289
+
tracing::trace!(
292
290
child_index,
293
291
utf16_offset = utf16_offset_in_container,
294
292
"dom_position_to_text_offset: node is container, using child index"
···
387
385
388
386
// Check if position is valid (not on invisible content).
389
387
if is_valid_cursor_position(¶.offset_map, char_offset) {
390
390
-
tracing::debug!(
388
388
+
tracing::trace!(
391
389
char_offset,
392
390
"dom_position_to_text_offset: returning valid position from mapping"
393
391
);
···
398
396
if let Some(snapped) =
399
397
find_nearest_valid_position(¶.offset_map, char_offset, direction_hint)
400
398
{
401
401
-
tracing::debug!(
399
399
+
tracing::trace!(
402
400
original = char_offset,
403
401
snapped = snapped.char_offset(),
404
402
"dom_position_to_text_offset: snapped from invisible to valid"
···
407
405
}
408
406
409
407
// Fallback to original if no snap target.
410
410
-
tracing::debug!(
408
408
+
tracing::trace!(
411
409
char_offset,
412
410
"dom_position_to_text_offset: returning original (no snap target)"
413
411
);
···
422
420
if utf16_offset_in_container > max_end {
423
421
// Cursor is past the end of tracked content - snap to end of last mapping.
424
422
let char_offset = mapping.char_range.end;
425
425
-
tracing::debug!(
423
423
+
tracing::trace!(
426
424
node_id = %node_id,
427
425
utf16_offset = utf16_offset_in_container,
428
426
max_tracked_end = max_end,
···
440
438
.and_then(|rest| rest.split('-').next())
441
439
.and_then(|idx_str| idx_str.parse::<usize>().ok());
442
440
443
443
-
tracing::debug!(
441
441
+
tracing::trace!(
444
442
node_id = %node_id,
445
443
utf16_offset = utf16_offset_in_container,
446
444
para_idx_from_node = ?para_idx_from_node,
···
454
452
if let Some(snapped) =
455
453
find_nearest_valid_position(¶.offset_map, para.char_range.start, direction_hint)
456
454
{
457
457
-
tracing::debug!(
455
455
+
tracing::trace!(
458
456
para_id = %para.id,
459
457
snapped_offset = snapped.char_offset(),
460
458
"dom_position_to_text_offset: fallback to matching paragraph"
···
469
467
if let Some(snapped) =
470
468
find_nearest_valid_position(¶.offset_map, para.char_range.start, direction_hint)
471
469
{
472
472
-
tracing::debug!(
470
470
+
tracing::trace!(
473
471
para_id = %para.id,
474
472
snapped_offset = snapped.char_offset(),
475
473
"dom_position_to_text_offset: fallback to first available paragraph"
···
643
641
let expected_len = new_para.byte_range.end - new_para.byte_range.start;
644
642
let dom_len = dom_text.len();
645
643
let matches = dom_len == expected_len;
646
646
-
tracing::debug!(
644
644
+
tracing::trace!(
647
645
para_id = %para_id,
648
646
dom_len,
649
647
expected_len,
···
689
687
.map(|p| p.now())
690
688
{
691
689
let elapsed_ms = end_time - start_time;
692
692
-
tracing::debug!(
690
690
+
tracing::trace!(
693
691
para_id = %para_id,
694
692
is_cursor_para,
695
693
elapsed_ms,
+209
docs/graph-data.json
···
2254
2254
"created_at": "2026-01-07T19:55:00.600569229-05:00",
2255
2255
"updated_at": "2026-01-07T19:55:00.600569229-05:00",
2256
2256
"metadata_json": "{\"confidence\":95}"
2257
2257
+
},
2258
2258
+
{
2259
2259
+
"id": 207,
2260
2260
+
"change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
2261
2261
+
"node_type": "goal",
2262
2262
+
"title": "Fix editor cursor/navigation bugs reported by users",
2263
2263
+
"description": null,
2264
2264
+
"status": "pending",
2265
2265
+
"created_at": "2026-01-07T21:15:29.543538706-05:00",
2266
2266
+
"updated_at": "2026-01-07T21:15:29.543538706-05:00",
2267
2267
+
"metadata_json": "{\"confidence\":90,\"prompt\":\"User reported multiple cursor bugs: jumping to position 0, blank line navigation, arrow key issues\"}"
2268
2268
+
},
2269
2269
+
{
2270
2270
+
"id": 208,
2271
2271
+
"change_id": "7b7accb1-8c16-4015-9182-103d2969cbf0",
2272
2272
+
"node_type": "outcome",
2273
2273
+
"title": "Blank line navigation fix - acceptable",
2274
2274
+
"description": null,
2275
2275
+
"status": "pending",
2276
2276
+
"created_at": "2026-01-07T21:15:35.376075796-05:00",
2277
2277
+
"updated_at": "2026-01-07T21:15:35.376075796-05:00",
2278
2278
+
"metadata_json": "{\"confidence\":75,\"prompt\":\"Changed gap emission: first newline=ZWSP only, additional newlines=literal newline+ZWSP. Browser can now navigate to blank lines, some minor cursor jank remains but usable.\"}"
2279
2279
+
},
2280
2280
+
{
2281
2281
+
"id": 209,
2282
2282
+
"change_id": "b2c90081-c941-4f18-88a3-28a7e11a79e6",
2283
2283
+
"node_type": "observation",
2284
2284
+
"title": "Login hang after OAuth callback - fixed",
2285
2285
+
"description": null,
2286
2286
+
"status": "pending",
2287
2287
+
"created_at": "2026-01-07T21:15:45.287601993-05:00",
2288
2288
+
"updated_at": "2026-01-07T21:15:45.287601993-05:00",
2289
2289
+
"metadata_json": "{\"confidence\":95,\"prompt\":\"Added early exit in restore_session when already authenticated\"}"
2290
2290
+
},
2291
2291
+
{
2292
2292
+
"id": 210,
2293
2293
+
"change_id": "b013b975-f1a7-459c-b369-7a9edc1d6f4b",
2294
2294
+
"node_type": "observation",
2295
2295
+
"title": "Ctrl+A select all - fixed by letting browser handle natively",
2296
2296
+
"description": null,
2297
2297
+
"status": "pending",
2298
2298
+
"created_at": "2026-01-07T21:15:49.045740296-05:00",
2299
2299
+
"updated_at": "2026-01-07T21:15:49.045740296-05:00",
2300
2300
+
"metadata_json": "{\"confidence\":95}"
2301
2301
+
},
2302
2302
+
{
2303
2303
+
"id": 211,
2304
2304
+
"change_id": "d9d668e9-960f-423d-ae32-8c4c0ecae1e6",
2305
2305
+
"node_type": "observation",
2306
2306
+
"title": "Long line overflow - fixed with overflow-wrap CSS",
2307
2307
+
"description": null,
2308
2308
+
"status": "pending",
2309
2309
+
"created_at": "2026-01-07T21:15:53.560541581-05:00",
2310
2310
+
"updated_at": "2026-01-07T21:15:53.560541581-05:00",
2311
2311
+
"metadata_json": "{\"confidence\":90}"
2312
2312
+
},
2313
2313
+
{
2314
2314
+
"id": 212,
2315
2315
+
"change_id": "ab71b5ea-a010-42bb-a113-ae6a2ec2fe4e",
2316
2316
+
"node_type": "observation",
2317
2317
+
"title": "Enter 4+ times cursor jump - potentially fixed by gap emission changes",
2318
2318
+
"description": null,
2319
2319
+
"status": "pending",
2320
2320
+
"created_at": "2026-01-07T21:15:58.586155730-05:00",
2321
2321
+
"updated_at": "2026-01-07T21:15:58.586155730-05:00",
2322
2322
+
"metadata_json": "{\"confidence\":40}"
2323
2323
+
},
2324
2324
+
{
2325
2325
+
"id": 213,
2326
2326
+
"change_id": "a041c1fb-3253-409a-aae7-a558187d99e4",
2327
2327
+
"node_type": "observation",
2328
2328
+
"title": "Double return behavior - potentially fixed by gap emission changes",
2329
2329
+
"description": null,
2330
2330
+
"status": "pending",
2331
2331
+
"created_at": "2026-01-07T21:16:03.703238206-05:00",
2332
2332
+
"updated_at": "2026-01-07T21:16:03.703238206-05:00",
2333
2333
+
"metadata_json": "{\"confidence\":35}"
2334
2334
+
},
2335
2335
+
{
2336
2336
+
"id": 214,
2337
2337
+
"change_id": "252761df-21fe-408b-902d-fbd00252efbc",
2338
2338
+
"node_type": "observation",
2339
2339
+
"title": "Selecting/deleting links - still open, needs verification",
2340
2340
+
"description": null,
2341
2341
+
"status": "pending",
2342
2342
+
"created_at": "2026-01-07T21:16:07.366725128-05:00",
2343
2343
+
"updated_at": "2026-01-07T21:16:07.366725128-05:00",
2344
2344
+
"metadata_json": "{\"confidence\":20}"
2257
2345
}
2258
2346
],
2259
2347
"edges": [
···
4434
4522
"weight": 1.0,
4435
4523
"rationale": "CSS fix for word wrapping",
4436
4524
"created_at": "2026-01-07T19:55:00.626395757-05:00"
4525
4525
+
},
4526
4526
+
{
4527
4527
+
"id": 200,
4528
4528
+
"from_node_id": 207,
4529
4529
+
"to_node_id": 208,
4530
4530
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4531
4531
+
"to_change_id": "7b7accb1-8c16-4015-9182-103d2969cbf0",
4532
4532
+
"edge_type": "leads_to",
4533
4533
+
"weight": 1.0,
4534
4534
+
"rationale": "Implemented gap emission fix for blank line navigation",
4535
4535
+
"created_at": "2026-01-07T21:15:39.826116361-05:00"
4536
4536
+
},
4537
4537
+
{
4538
4538
+
"id": 201,
4539
4539
+
"from_node_id": 207,
4540
4540
+
"to_node_id": 209,
4541
4541
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4542
4542
+
"to_change_id": "b2c90081-c941-4f18-88a3-28a7e11a79e6",
4543
4543
+
"edge_type": "leads_to",
4544
4544
+
"weight": 1.0,
4545
4545
+
"rationale": "Fixed during bug investigation",
4546
4546
+
"created_at": "2026-01-07T21:16:13.866616170-05:00"
4547
4547
+
},
4548
4548
+
{
4549
4549
+
"id": 202,
4550
4550
+
"from_node_id": 207,
4551
4551
+
"to_node_id": 210,
4552
4552
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4553
4553
+
"to_change_id": "b013b975-f1a7-459c-b369-7a9edc1d6f4b",
4554
4554
+
"edge_type": "leads_to",
4555
4555
+
"weight": 1.0,
4556
4556
+
"rationale": "Fixed during bug investigation",
4557
4557
+
"created_at": "2026-01-07T21:16:14.010017763-05:00"
4558
4558
+
},
4559
4559
+
{
4560
4560
+
"id": 203,
4561
4561
+
"from_node_id": 207,
4562
4562
+
"to_node_id": 211,
4563
4563
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4564
4564
+
"to_change_id": "d9d668e9-960f-423d-ae32-8c4c0ecae1e6",
4565
4565
+
"edge_type": "leads_to",
4566
4566
+
"weight": 1.0,
4567
4567
+
"rationale": "Fixed during bug investigation",
4568
4568
+
"created_at": "2026-01-07T21:16:14.108510907-05:00"
4569
4569
+
},
4570
4570
+
{
4571
4571
+
"id": 204,
4572
4572
+
"from_node_id": 207,
4573
4573
+
"to_node_id": 212,
4574
4574
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4575
4575
+
"to_change_id": "ab71b5ea-a010-42bb-a113-ae6a2ec2fe4e",
4576
4576
+
"edge_type": "leads_to",
4577
4577
+
"weight": 1.0,
4578
4578
+
"rationale": "May be fixed by gap emission changes",
4579
4579
+
"created_at": "2026-01-07T21:16:14.231726582-05:00"
4580
4580
+
},
4581
4581
+
{
4582
4582
+
"id": 205,
4583
4583
+
"from_node_id": 207,
4584
4584
+
"to_node_id": 213,
4585
4585
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4586
4586
+
"to_change_id": "a041c1fb-3253-409a-aae7-a558187d99e4",
4587
4587
+
"edge_type": "leads_to",
4588
4588
+
"weight": 1.0,
4589
4589
+
"rationale": "May be fixed by gap emission changes",
4590
4590
+
"created_at": "2026-01-07T21:16:14.330604847-05:00"
4591
4591
+
},
4592
4592
+
{
4593
4593
+
"id": 206,
4594
4594
+
"from_node_id": 207,
4595
4595
+
"to_node_id": 214,
4596
4596
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4597
4597
+
"to_change_id": "252761df-21fe-408b-902d-fbd00252efbc",
4598
4598
+
"edge_type": "leads_to",
4599
4599
+
"weight": 1.0,
4600
4600
+
"rationale": "Still needs investigation",
4601
4601
+
"created_at": "2026-01-07T21:16:14.411257422-05:00"
4602
4602
+
},
4603
4603
+
{
4604
4604
+
"id": 207,
4605
4605
+
"from_node_id": 207,
4606
4606
+
"to_node_id": 203,
4607
4607
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4608
4608
+
"to_change_id": "7f5f61d9-67a2-4743-bf6e-64df19ee991c",
4609
4609
+
"edge_type": "leads_to",
4610
4610
+
"weight": 1.0,
4611
4611
+
"rationale": "Previously fixed wikilink issue",
4612
4612
+
"created_at": "2026-01-07T21:16:32.811831732-05:00"
4613
4613
+
},
4614
4614
+
{
4615
4615
+
"id": 208,
4616
4616
+
"from_node_id": 207,
4617
4617
+
"to_node_id": 204,
4618
4618
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4619
4619
+
"to_change_id": "5bddd314-fd5a-487b-b9fb-25a7150a71ed",
4620
4620
+
"edge_type": "leads_to",
4621
4621
+
"weight": 1.0,
4622
4622
+
"rationale": "Previously fixed blockquote issue",
4623
4623
+
"created_at": "2026-01-07T21:16:32.828122843-05:00"
4624
4624
+
},
4625
4625
+
{
4626
4626
+
"id": 209,
4627
4627
+
"from_node_id": 207,
4628
4628
+
"to_node_id": 205,
4629
4629
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4630
4630
+
"to_change_id": "2e1776c7-94aa-47f4-b1b3-63898529335e",
4631
4631
+
"edge_type": "leads_to",
4632
4632
+
"weight": 1.0,
4633
4633
+
"rationale": "Fixed login hang",
4634
4634
+
"created_at": "2026-01-07T21:16:32.844654254-05:00"
4635
4635
+
},
4636
4636
+
{
4637
4637
+
"id": 210,
4638
4638
+
"from_node_id": 207,
4639
4639
+
"to_node_id": 206,
4640
4640
+
"from_change_id": "6e278837-7bb3-40dd-aad7-467036dff90b",
4641
4641
+
"to_change_id": "2ff2950e-e749-4d6e-b524-27217a323be0",
4642
4642
+
"edge_type": "leads_to",
4643
4643
+
"weight": 1.0,
4644
4644
+
"rationale": "Fixed overflow",
4645
4645
+
"created_at": "2026-01-07T21:16:32.861314215-05:00"
4437
4646
}
4438
4647
]
4439
4648
}