Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ec1979f
增加了跳转功能
BenPaoDeXiaoZhi Jul 20, 2025
77f843a
更新了名称
BenPaoDeXiaoZhi Jul 21, 2025
f0e50d5
增加了返回功能
BenPaoDeXiaoZhi Jul 22, 2025
f4725cc
清除了一些日志信息
BenPaoDeXiaoZhi Jul 22, 2025
b5be7bb
添加了注释
BenPaoDeXiaoZhi Jul 22, 2025
43d9c2f
更新了移除跳转事件的功能
BenPaoDeXiaoZhi Jul 22, 2025
03e77da
modified: src/plugins/find-definition/index.js
BenPaoDeXiaoZhi Jul 25, 2025
3a545d6
更新了判断逻辑,尝试加快搜索速度
BenPaoDeXiaoZhi Jul 25, 2025
5f9af27
清除调试信息,修改开发者信息
BenPaoDeXiaoZhi Jul 25, 2025
8d44880
createTypeDefinition
BenPaoDeXiaoZhi Jul 29, 2025
d374d0c
在当前分支中不提交wpp补全插件
BenPaoDeXiaoZhi Jul 29, 2025
83bff30
在当前分支中不追踪typeDefinition
BenPaoDeXiaoZhi Jul 29, 2025
ab1b419
deleted: src/plugins/extension-type-definition/index.js
BenPaoDeXiaoZhi Jul 29, 2025
585b1e3
删除了不可达的文件引用
BenPaoDeXiaoZhi Jul 29, 2025
a10a284
更新了对于函数名中含下划线以及名称最后任意数量空格的支持
BenPaoDeXiaoZhi Jul 29, 2025
b6eb646
更新了数字匹配、变量名匹配、let匹配
BenPaoDeXiaoZhi Jul 30, 2025
5f015f6
更新了字符串匹配
BenPaoDeXiaoZhi Jul 30, 2025
e54cc07
更新了break和continue,删除了不支持的后行断言
BenPaoDeXiaoZhi Jul 31, 2025
cbabc51
更新了关键字提示
BenPaoDeXiaoZhi Jul 31, 2025
d5b60ca
创建 index.js
BenPaoDeXiaoZhi Aug 5, 2025
b2cb085
更新 index.js
BenPaoDeXiaoZhi Aug 5, 2025
959a06a
更新了自动缩进、否则如果
BenPaoDeXiaoZhi Aug 8, 2025
b575aa0
更新事件跟踪
BenPaoDeXiaoZhi Aug 14, 2025
f435ef9
a
BenPaoDeXiaoZhi Oct 12, 2025
5b7e3a0
手滑了...
BenPaoDeXiaoZhi Oct 12, 2025
f0183d2
Merge branch 'Gandi-IDE:main' into main
BenPaoDeXiaoZhi Oct 12, 2025
fbf02d8
使用ts,加速,修改部分注释
BenPaoDeXiaoZhi Oct 12, 2025
5f423f6
更新 index.ts
BenPaoDeXiaoZhi Oct 12, 2025
7e41816
更新 index.ts
BenPaoDeXiaoZhi Oct 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@
# style types
*.less.d.ts

temp-wrapper.jsx
temp-wrapper.jsx
#ignore for branch-wppMonaco
/src/plugins/extension-type-definition
9 changes: 8 additions & 1 deletion src/l10n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,5 +283,12 @@
"plugins.cleanPro.description": "Clean Blocks Pro! Quickly clean headless blocks~",
"plugins.cleanPro.docs": "###### Plugin Usage Instructions\nRight-click in the code area, select【Clean Headless Blocks】to delete all【blocks without head connections】and【head blocks without subsequent connections】in the current character\n###### Plugin Usage Background\n1.Reduce test block accumulation to reduce lag\n2.Increase code readability\n3.Facilitate sharing, reduce project file size\n4.When creating a hot update for a work, it can be used to purify the work file, preventing headless blocks from interfering\n 5.……",
"plugins.cleanPro.cleanHeadlessBlocks": "Clean Headless Blocks",
"plugins.cleanPro.docs.title": "Plugin Doc"
"plugins.cleanPro.docs.title": "Plugin Doc",
"plugins.findDefinition.title": "find definition of custom block",
"plugins.findDefinition.description": "Right-click on a custom block in the code area and select【Jump To Definition】to jump to the definition location of that custom block.",
"plugins.findDefinition.goToDefinition": "Jump To Definition",
"plugins.extensionTypeDefinition.title": "Provide auto-completion for extensions development",
"plugins.extensionTypeDefinition.description": "After loading, type annotations will be automatically provided. By annotating variable types using jsdoc syntax, you can enjoy auto-completion. For example, \n/**\n* @type {Runtime}\n*/\nlet runtime;\nWhen typing \"runtime.\", it will prompt you with the methods supported by runtime",
"plugins.wppMonaco.title": "Provide highlight and auto-completion for wpp",
"plugins.wppMonaco.description": "Create .wpp file, and enjoy the highlight and auto-completion!"
}
9 changes: 8 additions & 1 deletion src/l10n/zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,5 +284,12 @@
"plugins.cleanPro.description": "整理积木 Pro!快速清理无头积木~",
"plugins.cleanPro.docs": "###### 插件使用方法\n在代码区按下【右键】,点击【清理无头块】即可删除当前角色内全部【没有头积木拼接的积木】和【没有后续拼接的头积木】\n###### 插件使用背景\n1.减少测试块堆积,以减少卡顿\n2.增加代码可读性\n3.便于分享,减少工程文件体积\n4.制作作品热更新时,可用于净化作品文件,防止无头块干扰\n 5.……",
"plugins.cleanPro.cleanHeadlessBlocks": "清理无头块",
"plugins.cleanPro.docs.title": "插件文档"
"plugins.cleanPro.docs.title": "插件文档",
"plugins.findDefinition.title": "查找自定义块的定义位置",
"plugins.findDefinition.description": "在代码区右键单击自定义块,选择【跳转到定义】即可跳转到该自定义块的定义位置。",
"plugins.findDefinition.goToDefinition": "跳转到定义",
"plugins.extensionTypeDefinition.title": "为拓展开发提供自动补全",
"plugins.extensionTypeDefinition.description": "加载之后,会自动提供类型标注,使用jsdoc语法标注了变量类型后可以提供自动补全,如\n/**\n* @type{Runtime}\n*/\nlet runtime;\n键入\"runtime.\"后会提示runtime支持的方法",
"plugins.wppMonaco.title": "为白猫的解释器语言提供高亮与补全",
"plugins.wppMonaco.description": "在文件管理中新建wpp文件,立享补全与高亮!"
}
2 changes: 2 additions & 0 deletions src/plugins-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ export default {
"data-category-tweaks": () => import(/* webpackChunkName: "plugin-data-category-tweaks" */ "plugins/data-category-tweaks"),
"mobile-code-batch-select": () => import(/* webpackChunkName: "plugin-mobile-code-batch-select" */ "src/plugins/mobile-code-batch-select"),
"clean-pro": () => import(/* webpackChunkName: "plugin-clean-pro" */ "src/plugins/clean-pro"),
"find-definition": () => import(/* webpackChunkName: "plugin-find-definition" */ "src/plugins/find-definition"),
// "extension-type-definition": () => import(/* webpackChunkName: "plugin-extension-type-definition" */ "plugins/extension-type-definition"),
} as const;
4 changes: 4 additions & 0 deletions src/plugins-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import costumePiskel from "src/plugins/costume-piskel/manifest";
import dataCategoryTweaks from "plugins/data-category-tweaks/manifest";
import mobileCodeBatchSelect from "src/plugins/mobile-code-batch-select/manifest";
import cleanPro from "src/plugins/clean-pro/manifest";
import findDefinition from "src/plugins/find-definition/manifest";
// import extensionTypeDefinition from "plugins/extension-type-definition/manifest";

export default {
folder,
Expand All @@ -48,4 +50,6 @@ export default {
"data-category-tweaks": dataCategoryTweaks,
"mobile-code-batch-select": mobileCodeBatchSelect,
"clean-pro": cleanPro,
"find-definition": findDefinition,
// "extension-type-definition": extensionTypeDefinition,
};
233 changes: 233 additions & 0 deletions src/plugins/find-definition/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import { scrollBlockIntoView } from "utils/block-helper";

//类型定义中...
type ContextMenuFunction = (options: Array<BlockMenuOption>) => void;

interface BlockMenuOption {
text: string;
enabled: boolean;
callback: Function;
}

interface IBlockly{
getMainWorkspace(): Blockly.WorkspaceSvg;
Events: {
Abstract:any
}
}

interface ProcedureBlockSVG extends Blockly.BlockSvg{
isGlobal_:boolean; //是否为全局块
procCode_:string; //对应的积木名称
}
//---

let PROTOTYPE_OPCODE: string,
CALL_OPCODE: string,
CALL_RETURN_OPCODE: string,
ORIGIN_CONTEXT_MENU: null | ContextMenuFunction;

const getBlockInMainWorkspace = (blockly: IBlockly, blockId: string) => {
const workspace = blockly.getMainWorkspace();
if (!workspace) {
console.warn("没有工作区,无法获取块");
return null;
}
const block = workspace.blockDB_[blockId];
if (!block) {
console.warn("没有找到块", blockId);
return null;
}
return block;
};

/**
* @param call_block 右键菜单的块
*/
const goToDefinition = (call_block: ProcedureBlockSVG, vm: VirtualMachine, workspace: Blockly.WorkspaceSvg, blockly: IBlockly) => {
const procCode = call_block.procCode_;
let prototypeBlockInTarget:Scratch.BlockState, targetId:string;
for (let block of Object.values(vm.editingTarget.blocks._blocks)) {
//在当前角色中寻找
if (
block.opcode === PROTOTYPE_OPCODE && //如果是定义块
block.mutation.proccode === procCode //并且定义块的procCode与调用块的procCode相同
) {
prototypeBlockInTarget = block;
targetId = vm.editingTarget.id;
break;
}
}
if (
!prototypeBlockInTarget && //在当前角色中未找到
call_block.isGlobal_ //可能在全局中
) {
const moduleName = call_block.procCode_.split('.')[0]
const moduleTargets = vm.runtime.targets.filter((t)=>{
if(t.sprite.name.endsWith('/'+moduleName) && t.isModule){//这可能导致不是指定模块的模块被整进来,但还是比遍历每一个快多了
return true
}
return false
})
for (let target of moduleTargets) {
//遍历每一个模块,搜索自制积木的定义块
if (target.isModule) {
for (let block of Object.values(target.blocks._blocks)) {
if (
block.opcode === PROTOTYPE_OPCODE && //如果是定义块
block.mutation.proccode === procCode && //并且定义块的procCode与调用块的procCode相同
block.mutation.isglobal === "true" //并且是全局的
) {
prototypeBlockInTarget = block;
targetId = target.id;
break;
}
}
}
}
}

if (!prototypeBlockInTarget) {
console.warn("没有找到定义块,无法跳转");
return;
}

const src_target_id = vm.editingTarget.id; //记录调用自制积木的角色id
const dst_target_id = targetId; //记录定义自制积木的角色id
if (targetId !== vm.editingTarget.id) {
vm.setEditingTarget(targetId);
}

const prototypeBlock = getBlockInMainWorkspace(blockly, prototypeBlockInTarget.id);
const definitionBlock:Blockly.Block = prototypeBlock.parentBlock_; //prototype无法进行跳转,所以需要获取其父块definition
scrollBlockIntoView(definitionBlock, workspace);
class MoveWorkspaceEvent extends blockly.Events.Abstract {
type: 'GOTO_DEF';
src_target_id: string;
src_block_id: string;
dst_target_id: string;
dst_block_id: string;
workspace: Blockly.WorkspaceSvg;
recordUndo:boolean;
constructor(
src_target_id: string,
src_block_id: string,
dst_target_id: string,
dst_block_id: string,
workspace: Blockly.WorkspaceSvg,
) {
super();
this.type = "GOTO_DEF";
this.src_target_id = src_target_id;
this.src_block_id = src_block_id;
this.dst_target_id = dst_target_id;
this.dst_block_id = dst_block_id;
this.workspace = workspace;
this.recordUndo = true; //记录撤销
}
/**
* 执行撤销或重做
* @param redo 为重做?
*/
run(redo:boolean) {
if (redo) {
vm.setEditingTarget(this.dst_target_id);
scrollBlockIntoView(getBlockInMainWorkspace(blockly, this.dst_block_id), this.workspace); //跳转至定义(要通过id获取,否则跨角色会获取失败)
} else {
vm.setEditingTarget(this.src_target_id);
scrollBlockIntoView(getBlockInMainWorkspace(blockly, this.src_block_id), this.workspace); //跳转回引用
}
}
}
workspace.fireChangeListener(
(
new MoveWorkspaceEvent(src_target_id, call_block.id, dst_target_id, definitionBlock.id, workspace)as any
),
); //记录跳转事件
};

const handleGoToDefinition = function (vm, blockly) {
if (!this.getProcCode) {
console.warn("没有procCode,无法跳转");
return;
}
goToDefinition(this, vm, blockly.getMainWorkspace(), blockly);
};

function refreshBlocksMenuWithOpcodes(
blockly: typeof Blockly & { getMainWorkspace: () => Blockly.WorkspaceSvg },
opcodes: Array<string>,
newCtxFunc: (options:Array<BlockMenuOption>)=>void
) {
for (let block of blockly.getMainWorkspace().getAllBlocks()) {
if (opcodes.includes(block.type)) {
(block as Blockly.Block & { customContextMenu: ContextMenuFunction}).customContextMenu =
newCtxFunc;
}
}
(blockly.getMainWorkspace().getToolbox() as Blockly.Toolbox & {showAll_:()=>void}).showAll_();
}

function FindDefinition({ blockly, vm, registerSettings, msg }: PluginContext): { dispose: () => void } {
if (blockly.Blocks[blockly.PROCEDURES_CALL_BLOCK_TYPE]) {
PROTOTYPE_OPCODE = blockly.PROCEDURES_PROTOTYPE_BLOCK_TYPE;
CALL_OPCODE = blockly.PROCEDURES_CALL_BLOCK_TYPE;
CALL_RETURN_OPCODE = blockly.PROCEDURES_CALL_WITH_RETURN_BLOCK_TYPE;
const ctxMenuClass: { customContextMenu: ContextMenuFunction } =
blockly.ScratchBlocks.VerticalExtensions.PROCEDURE_CALL_CONTEXTMENU;
ORIGIN_CONTEXT_MENU = ctxMenuClass.customContextMenu;
ctxMenuClass.customContextMenu = function (menuOptions: Array<BlockMenuOption>) {
if (ORIGIN_CONTEXT_MENU === null) {
console.warn("菜单未刷新,可尝试切换角色"); //一般不会运行,因为删除插件时会刷新
return;
}
ORIGIN_CONTEXT_MENU.call(this, menuOptions); //调用原有菜单
menuOptions.push({
//加入自定义菜单项
text: msg("plugins.findDefinition.goToDefinition"),
enabled: true,
callback: handleGoToDefinition.bind(this, vm, blockly),
});
};
refreshBlocksMenuWithOpcodes(blockly, [CALL_OPCODE, CALL_RETURN_OPCODE], ctxMenuClass.customContextMenu);
}
const register = registerSettings(
msg("plugins.findDefinition.title"),
"plugin-find-definition",
[
{
key: "plugin-find-definition",
label: msg("plugins.findDefinition.title"),
description: msg("plugins.findDefinition.description"),
items: [],
},
],
"",
);
return {
dispose: () => {
/** Remove some side effects */
const ctxMenuClass: { customContextMenu: ContextMenuFunction } =
blockly.ScratchBlocks.VerticalExtensions.PROCEDURE_CALL_CONTEXTMENU;
ctxMenuClass.customContextMenu = ORIGIN_CONTEXT_MENU
ORIGIN_CONTEXT_MENU = undefined;
const workspace = blockly.getMainWorkspace();
if (!workspace) {
console.warn("没有工作区,无法删除原有菜单");
return;
}
refreshBlocksMenuWithOpcodes(blockly, [CALL_OPCODE, CALL_RETURN_OPCODE], ctxMenuClass.customContextMenu);
// workspace.clearUndo(); 我不想使用这个,因为会清除所有撤销记录
// 可能导致用户无法撤销之前的操作
// 但可以通过遍历undoStack并删除的方式来清除跳转事件
const new_undo_stack = workspace.undoStack_.filter((event) => event.type !== "GOTO_DEF");
workspace.undoStack_ = new_undo_stack;
//同时,也需要删除redoStack
const new_redo_stack = workspace.redoStack_.filter((event) => event.type !== "GOTO_DEF");
workspace.redoStack_ = new_redo_stack;
register.dispose();
},
};
}

export default FindDefinition;
11 changes: 11 additions & 0 deletions src/plugins/find-definition/manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
name: "find-definition",
type: "function",
description: "a plugin that can find where the definition of custom block is",
credits: [
{
name: "BenPaoDeXiaoZhi @ CCW",
link:"https://www.ccw.site/student/63c2807d669fa967f17f5559"
},
],
};
Empty file.
1 change: 1 addition & 0 deletions src/plugins/plugins-manager/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import styles from "./styles.less";
const ALL_PLUGINS = Object.keys(Plugins);
// When the line numbers of the variables below change, plopfile.js needs to be updated.
const DEFAULT_INJECT_PLUGINS = [
"find-definition",
"block-sharing",
"custom-plugin",
"folder",
Expand Down
5 changes: 5 additions & 0 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ declare module "*.svg" {
export default src;
}

declare module "*.asset" {
const data:string
export default data;
}

declare module "*.svg?url" {
const src: string;
export default src;
Expand Down
4 changes: 4 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ module.exports = {
},
module: {
rules: [
{
test: /\.asset$/i,
type: 'asset/source',
},
{
test: /\.tsx?$/,
use: "ts-loader",
Expand Down
4 changes: 4 additions & 0 deletions webpackDevServer.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ module.exports = {
},
module: {
rules: [
{
test: /\.asset$/i,
type: 'asset/source',
},
{
test: /\.tsx?$/,
use: "ts-loader",
Expand Down