Skip to content

Commit df487af

Browse files
Merge remote-tracking branch 'matt/line-cursor-patch' into april-ut
2 parents 5cfc40d + 590db72 commit df487af

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

src/line_cursor_patch.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import * as Blockly from 'blockly/core';
8+
9+
export const applyLineCursorPatch = () => {
10+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
11+
(Blockly.LineCursor.prototype as any).getLastNode = function (
12+
isValid: (p1: Blockly.ASTNode | null) => boolean,
13+
): Blockly.ASTNode | null {
14+
// Loop back to last block if it exists.
15+
const topBlocks = this.workspace.getTopBlocks(true);
16+
if (!topBlocks.length) return null;
17+
18+
// Find the last stack.
19+
const lastTopBlockNode = Blockly.ASTNode.createStackNode(
20+
topBlocks[topBlocks.length - 1],
21+
);
22+
let prevNode = lastTopBlockNode;
23+
let nextNode: Blockly.ASTNode | null = lastTopBlockNode;
24+
// Iterate until you fall off the end of the stack.
25+
while (nextNode) {
26+
prevNode = nextNode;
27+
nextNode = this.getNextNode(prevNode, isValid, false);
28+
}
29+
return prevNode;
30+
};
31+
32+
Blockly.LineCursor.prototype.prev = function (): Blockly.ASTNode | null {
33+
const curNode = this.getCurNode();
34+
if (!curNode) {
35+
return null;
36+
}
37+
const newNode = this.getPreviousNode(
38+
curNode,
39+
// @ts-expect-error accessing private method
40+
this.validLineNode.bind(this),
41+
true,
42+
);
43+
if (newNode) {
44+
this.setCurNode(newNode);
45+
}
46+
return newNode;
47+
};
48+
49+
Blockly.LineCursor.prototype.out = function (): Blockly.ASTNode | null {
50+
const curNode = this.getCurNode();
51+
if (!curNode) {
52+
return null;
53+
}
54+
const newNode = this.getPreviousNode(
55+
curNode,
56+
// @ts-expect-error accessing private method
57+
this.validInLineNode.bind(this),
58+
true,
59+
);
60+
61+
if (newNode) {
62+
this.setCurNode(newNode);
63+
}
64+
return newNode;
65+
};
66+
67+
Blockly.LineCursor.prototype.getPreviousNode = function (
68+
node: Blockly.ASTNode | null,
69+
isValid: (p1: Blockly.ASTNode | null) => boolean,
70+
loop: boolean,
71+
): Blockly.ASTNode | null {
72+
if (!node) return null;
73+
// @ts-expect-error accessing private method
74+
const potential = this.getPreviousNodeImpl(node, isValid);
75+
if (potential || !loop) return potential;
76+
// Loop back.
77+
// @ts-expect-error passing unexpected arg
78+
const lastNode = this.getLastNode(isValid);
79+
if (isValid(lastNode)) return lastNode;
80+
// @ts-expect-error accessing private method
81+
return this.getPreviousNodeImpl(lastNode, isValid);
82+
};
83+
84+
// @ts-expect-error accessing protected method
85+
Blockly.LineCursor.prototype.validLineNode = function (
86+
node: Blockly.ASTNode | null,
87+
): boolean {
88+
if (!node) return false;
89+
const location = node.getLocation();
90+
const type = node && node.getType();
91+
switch (type) {
92+
case Blockly.ASTNode.types.BLOCK:
93+
return !(location as Blockly.Block).outputConnection?.isConnected();
94+
default:
95+
return false;
96+
}
97+
};
98+
99+
// @ts-expect-error accessing protected method
100+
Blockly.LineCursor.prototype.validInLineNode = function (
101+
node: Blockly.ASTNode | null,
102+
): boolean {
103+
if (!node) return false;
104+
// @ts-expect-error accessing private method
105+
if (this.validLineNode(node)) return true;
106+
const location = node.getLocation();
107+
const type = node && node.getType();
108+
switch (type) {
109+
case Blockly.ASTNode.types.BLOCK:
110+
return true;
111+
case Blockly.ASTNode.types.INPUT: {
112+
const connection = location as Blockly.Connection;
113+
return (
114+
connection.type !== Blockly.ConnectionType.NEXT_STATEMENT &&
115+
connection.type !== Blockly.ConnectionType.PREVIOUS_STATEMENT &&
116+
!connection.isConnected()
117+
);
118+
}
119+
case Blockly.ASTNode.types.FIELD: {
120+
const field = node.getLocation() as Blockly.Field;
121+
return !(
122+
field.getSourceBlock()?.isSimpleReporter() && field.isFullBlockField()
123+
);
124+
}
125+
default:
126+
return false;
127+
}
128+
};
129+
};

src/navigation_controller.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ import {ActionMenu} from './actions/action_menu';
3737
import {MoveActions} from './actions/move';
3838
import {Mover} from './actions/mover';
3939
import {UndoRedoAction} from './actions/undo_redo';
40+
import {applyLineCursorPatch} from './line_cursor_patch';
41+
42+
applyLineCursorPatch();
4043

4144
const KeyCodes = BlocklyUtils.KeyCodes;
4245

0 commit comments

Comments
 (0)