@@ -39,20 +39,60 @@ function init(plugin)
3939 if ev .name == " OpenFile" then
4040 local opening_raw = RawDmi .opening
4141 RawDmi .after_open (app .sprite )
42-
42+ -- Collect all .dmi placeholder sprites first, then close them, then create editors.
43+ -- Calling Editor.new() -> app.events:on() inside an event callback can reallocate
44+ -- Aseprite's internal callback vector while Events::call is iterating it (use-after-free).
45+ local filenames = {}
4346 if app .sprite and app .sprite .filename :ends_with (" .dmi" ) and not opening_raw then
4447 local filename = app .sprite .filename
4548 app .command .CloseFile { ui = false }
4649
50+ -- Prevent duplicate editor instances for the same file
51+ local normalized = string.lower (filename )
52+ local found = false
53+ for _ , editor in ipairs (open_editors ) do
54+ if not editor .closed and string.lower (editor :path ()) == normalized then
55+ editor :repaint ()
56+ found = true
57+ break
58+ end
59+ end
60+
61+ if not found then
62+ table.insert (filenames , filename )
63+ end
64+ end
65+
66+ -- Now create editors outside the event callback
67+ if # filenames > 0 then
4768 loadlib (plugin .path )
48- Editor .new (DIALOG_NAME , filename )
69+ for _ , filename in ipairs (filenames ) do
70+ Editor .new (DIALOG_NAME , filename )
71+ end
4972 end
5073 elseif ev .name == " Exit" then
5174 exiting = true
5275 end
76+
77+ -- Dispatch to open editors. We do NOT register per-editor
78+ -- listeners because calling app.events:on() from inside an
79+ -- event callback can reallocate Aseprite's internal callback
80+ -- vector while Events::call is iterating it (use-after-free).
81+ for _ , editor in ipairs (open_editors ) do
82+ if not editor .closed then
83+ editor :onaftercommand (ev )
84+ end
85+ end
5386 end )
5487
5588 before_listener = app .events :on (" beforecommand" , function (ev )
89+ -- Dispatch to open editors first (same reason as aftercommand above).
90+ for _ , editor in ipairs (open_editors ) do
91+ if not editor .closed then
92+ editor :onbeforecommand (ev )
93+ end
94+ end
95+
5696 if RawDmi .beforecommand (ev ) then
5797 return
5898 elseif ev .name == " Exit" then
0 commit comments