@@ -79,7 +79,8 @@ export class LineCursor extends Marker {
7979 const markerManager = this . workspace . getMarkerManager ( ) ;
8080 this . oldCursor = markerManager . getCursor ( ) ;
8181 markerManager . setCursor ( this ) ;
82- if ( this . oldCursor ) this . setCurNode ( this . oldCursor . getCurNode ( ) ) ;
82+ const oldCursorNode = this . oldCursor ?. getCurNode ( ) ;
83+ if ( oldCursorNode ) this . setCurNode ( oldCursorNode ) ;
8384 this . workspace . addChangeListener ( this . selectListener ) ;
8485 this . installed = true ;
8586 }
@@ -423,7 +424,7 @@ export class LineCursor extends Marker {
423424 preDelete ( deletedBlock : Blockly . Block ) {
424425 const curNode = this . getCurNode ( ) ;
425426
426- const nodes : Blockly . ASTNode [ ] = [ curNode ] ;
427+ const nodes : Blockly . ASTNode [ ] = curNode ? [ curNode ] : [ ] ;
427428 // The connection to which the deleted block is attached.
428429 const parentConnection =
429430 deletedBlock . previousConnection ?. targetConnection ??
@@ -446,7 +447,7 @@ export class LineCursor extends Marker {
446447 }
447448 // A location on the workspace beneath the deleted block.
448449 // Move to the workspace.
449- const curBlock = curNode . getSourceBlock ( ) ;
450+ const curBlock = curNode ? .getSourceBlock ( ) ;
450451 if ( curBlock ) {
451452 const workspaceNode = Blockly . ASTNode . createWorkspaceNode (
452453 this . workspace ,
@@ -474,6 +475,40 @@ export class LineCursor extends Marker {
474475 throw new Error ( 'no valid nodes in this.potentialNodes' ) ;
475476 }
476477
478+ /**
479+ * Sets the object in charge of drawing the marker.
480+ *
481+ * We want to customize drawing, so rather than directly setting the given
482+ * object, we instead set a wrapper proxy object that passes through all
483+ * method calls and property accesses except for draw(), which it delegates
484+ * to the drawMarker() method in this class.
485+ *
486+ * @param drawer The object ~in charge of drawing the marker.
487+ */
488+ override setDrawer ( drawer : Blockly . blockRendering . MarkerSvg ) {
489+ const altDraw = function (
490+ this : LineCursor ,
491+ oldNode : ASTNode | null ,
492+ curNode : ASTNode | null ,
493+ ) {
494+ // Pass the unproxied, raw drawer object so that drawMarker can call its
495+ // `draw()` method without triggering infinite recursion.
496+ this . drawMarker ( oldNode , curNode , drawer ) ;
497+ } . bind ( this ) ;
498+
499+ super . setDrawer (
500+ new Proxy ( drawer , {
501+ get ( target : typeof drawer , prop : keyof typeof drawer ) {
502+ if ( prop === 'draw' ) {
503+ return altDraw ;
504+ }
505+
506+ return target [ prop ] ;
507+ } ,
508+ } ) ,
509+ ) ;
510+ }
511+
477512 /**
478513 * Set the location of the cursor and draw it.
479514 *
@@ -482,7 +517,7 @@ export class LineCursor extends Marker {
482517 *
483518 * @param newNode The new location of the cursor.
484519 */
485- override setCurNode ( newNode : ASTNode , selectionInSync = false ) {
520+ override setCurNode ( newNode : ASTNode | null , selectionInSync = false ) {
486521 if ( newNode ?. getLocation ( ) === this . getCurNode ( ) ?. getLocation ( ) ) {
487522 return ;
488523 }
@@ -505,18 +540,8 @@ export class LineCursor extends Marker {
505540 }
506541 }
507542
508- const oldNode = super . getCurNode ( ) ;
509- // Kludge: we can't set this.curNode directly, so we have to call
510- // super.setCurNode(...) to do it for us - but that would call
511- // this.drawer.draw(...), so prevent that by temporarily setting
512- // this.drawer to null (which we also can't do directly!)
513- const drawer = this . getDrawer ( ) ;
514- this . setDrawer ( null as any ) ; // Cast required since param is not nullable.
515543 super . setCurNode ( newNode ) ;
516- this . setDrawer ( drawer ) ;
517544
518- // Draw this marker the way we want to.
519- this . drawMarker ( oldNode , newNode ) ;
520545 // Try to scroll cursor into view.
521546 if ( newNode ?. getType ( ) === ASTNode . types . BLOCK ) {
522547 const block = newNode . getLocation ( ) as Blockly . BlockSvg ;
@@ -527,21 +552,6 @@ export class LineCursor extends Marker {
527552 }
528553 }
529554
530- /**
531- * Redraw the current marker.
532- *
533- * Overrides normal Marker drawing logic to use this.drawMarker()
534- * instead of this.drawer.draw() directly.
535- *
536- * This hooks the method used by the renderer to draw the marker,
537- * preventing the marker drawer from showing a marker if we don't
538- * want it to.
539- */
540- override draw ( ) {
541- const curNode = super . getCurNode ( ) ;
542- this . drawMarker ( curNode , curNode ) ;
543- }
544-
545555 /**
546556 * Draw this cursor's marker.
547557 *
@@ -566,7 +576,11 @@ export class LineCursor extends Marker {
566576 * @param oldNode The previous node.
567577 * @param curNode The current node.
568578 */
569- private drawMarker ( oldNode : ASTNode , curNode : ASTNode ) {
579+ private drawMarker (
580+ oldNode : ASTNode | null ,
581+ curNode : ASTNode | null ,
582+ realDrawer : Blockly . blockRendering . MarkerSvg ,
583+ ) {
570584 // If old node was a block, unselect it or remove fake selection.
571585 if ( oldNode ?. getType ( ) === ASTNode . types . BLOCK ) {
572586 const block = oldNode . getLocation ( ) as Blockly . BlockSvg ;
@@ -587,12 +601,12 @@ export class LineCursor extends Marker {
587601
588602 // If drawing can't be handled locally, just use the drawer.
589603 if ( curNodeType !== ASTNode . types . BLOCK && ! isZelosInputConnection ) {
590- this . getDrawer ( ) ? .draw ( oldNode , curNode ) ;
604+ realDrawer . draw ( oldNode , curNode ) ;
591605 return ;
592606 }
593607
594608 // Hide any visible marker SVG and instead do some manual rendering.
595- super . hide ( ) ; // Calls this.drawer?.hide().
609+ realDrawer . hide ( ) ;
596610
597611 if ( isZelosInputConnection ) {
598612 this . showAtInput ( curNode ) ;
@@ -607,7 +621,7 @@ export class LineCursor extends Marker {
607621
608622 // Call MarkerSvg.prototype.fireMarkerEvent like
609623 // MarkerSvg.prototype.draw would (even though it's private).
610- ( this . getDrawer ( ) as any ) ?. fireMarkerEvent ?.( oldNode , curNode ) ;
624+ ( realDrawer as any ) ?. fireMarkerEvent ?.( oldNode , curNode ) ;
611625 }
612626
613627 /**
0 commit comments